자바 동적 에이전트 정적 에이전트 실례 분석
예:집주인,세입 자,중개 와 같은 관계.중개(대리 대상)는 집주인(진실 대상)이 집 을 임대 하고 세입 자(고객)는 중개(대리 대상)를 통 해 집 을 찾 아 전 세 를 구하 고,중 개 는 전 세 를 마치 면 중개 수수료(부가 조작)를 받 을 수 있다.
먼저 정적 프 록 시 모드 를 살 펴 보고 위 에서 프 록 시 모드 에 대한 이 해 를 통 해 프 록 시 모드 를 알 수 있 습 니 다.즉,new 의 실제 대상 을 통 해 방법 을 호출 하지 않 고 프 록 시 대상 을 통 해 방법 을 호출 하기 때문에 프 록 시 대상 은 실제 대상 의 인용 을 포함 합 니 다.코드 를 보 겠 습 니 다.
인터페이스:Subject 는 하나의 방법 을 포함 합 니 다.
package com.example.designpattern.proxy;
public interface Subject {
void request();
}
RealSubject 클래스 는 Subject 인 터 페 이 스 를 실 현 했 습 니 다.간단하게 보기 위해 방법 은 간단하게 한 마디 를 출력 합 니 다.
package com.example.designpattern.proxy;
public class RealSubject implements Subject {
//
public void request() {
System.out.println("From real subject");
}
}
프 록 시 클래스 Proxy Subject 도 Subject 인 터 페 이 스 를 실현 하고 Subject 안의 방법 을 실현 해 야 하지만 여기 서 는 실제 대상 을 호출 하여 이 루어 집 니 다.
package com.example.designpattern.proxy;
public class ProxySubject implements Subject {
private RealSubject realSubject; //
//
public void request() {
this.preRequest(); //
if (realSubject == null){
realSubject = new RealSubject();
}
realSubject.request(); //
this.afterRequet(); //
}
//
private void preRequest(){
System.out.println("pre request");
}
//
private void afterRequet(){
System.out.println("after request");
}
}
클 라 이언 트 호출 자
package com.example.designpattern.proxy;
public class Client {
public static void main(String[] args) {
ProxySubject proxy = new ProxySubject();
//
proxy.request();
}
}
정적 에이전트:이 코드 들 을 실행 할 수 있 습 니 다.Client 클래스 에서 볼 수 있 습 니 다.프 록 시 Subject 의 대상 proxy 를 통 해 호출 하 는 방법 입 니 다.프 록 시 클래스 Proxy Subject 에서 실제 대상 의 인용 이 있 고 프 록 시 대상 에서 request()방법 으로 실제 대상 의 방법 을 호출 했 습 니 다.이런 모델 을 대리 모델 이 라 고 한다.
장점 은:
1.프 록 시 모드 는 프 록 시 대상 과 실제 대상 이 호출 된 대상 을 분리 할 수 있 습 니 다.
2.어느 정도 시스템 의 결합 도 를 낮 추고 확장 성 이 좋다.
프 록 시 클래스 에는 실제 주제 에 대한 인용 이 포함 되 어 있 습 니 다.이렇게 하 는 것 도 단점 이 있 습 니 다.
1.실제 대상 과 대리 류 가 일일이 대응 하고 진실 류 를 증가 하 는 것 도 대리 류 를 증가 해 야 한다.이렇게 하면 유형의 수량 을 신속하게 증가 시 켜 시스템 을 복잡 하 게 만 들 수 있다.
2.디자인 대리 이전에 실제 주 제 는 반드시 사전에 존재 해 야 하고 유연성 이 없다.
동적 대 리 를 사용 하면 상기 문 제 를 해결 할 수 있 습 니 다.동적 대 리 는 정적 대리 에 비해 서 입 니 다.
동적 생 성 인 스 턴 스 를 어떻게 실현 하 는 지 말 할 수 있 습 니 다.이전에 우리 가 만 든 인 스 턴 스 는 모두 new 방식 으로 이 루어 지지 않 았 습 니까?
Hello hi = new Hello();
그러면 동적 생 성 인 스 턴 스 는 자바 가 제공 하 는 기능 이 므 로 우리 가 new 대상 에 갈 필요 가 없습니다.그 는 정적 방법 인 Proxy.new Proxy Instance()를 정 의 했 습 니 다.매개 변수 호출 만 들 어 오 면 됩 니 다.자바 문서 에 있 습 니 다.그림 참조:
자바 표준 라 이브 러 리 는 동적 에이전트(DynamicProxy)의 메커니즘 을 제공 합 니 다.실행 기간 동안 특정한 interface 의 인 스 턴 스 를 동적 으로 만 들 수 있 습 니 다.
매개 변수 설명:
Proxy.newProxyInstance(
ClassLoader loader, // ClassLoader
Class<?>[] interfaces, //
InvocationHandler h); // InvocationHandler
다음은 동적 에이전트 예 코드 를 보 겠 습 니 다.Subject 인터페이스
package design.dynamicproxy;
public interface Subject {
void request(String str);
}
RealSubject 클래스 구현 Subject 인터페이스
package design.dynamicproxy;
public class RealSubject implements Subject {
@Override
public void request(String str) {
System.out.println("From Real Subject!" + " args:" + str );
}
}
동적 에이전트 류 DynamicSubject 는 Invocation Handler 를 실현 하고 invoke()방법 을 다시 작성 합 니 다.
package design.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Object , ,
* invoke() , method.invoke()
* object, object , ,
*
*/
public class DynamicSubject implements InvocationHandler {
// Object ,
private Object object;
public DynamicSubject(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling:" + method);
// realSubject request() , , Method
method.invoke(object, args);
System.out.println("after calling:" + method);
return null;
}
}
클 라 이언 트 클래스
package design.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
//
// class com.sun.proxy.$Proxy0 ,
Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),handler);
subject.request("eather");
System.out.println(subject.getClass());
// class com.sun.proxy.$Proxy0, Proxy.newProxyInstance()
}
}
Client 에서 볼 수 있 습 니 다.여기 서 호출 하 는 방법 은 subject.request("eather")입 니 다.이 대상 subject 는 new DynamicSubject()를 통 해 생 성 된 것 이 아니 라 자바 내부 에서 작성 한 방법 으로 실 행 될 때 동적 으로 대상 을 생 성 합 니 다.이 가능 하 다,~할 수 있다,...InvocationHandler handler = new DynamicSubject(realSubject);
여 기 는 new DynamicSubject(realSubject)를 통 해 가 아 닙 니 다.대상 이 생 겼 나 요?네,그렇지만 Invocation Handler 형식 입 니 다.주로 Invocation Handler 형식 인 자 를 Proxy.new Proxy Instance()에 전달 합 니 다.마지막 인자 입 니 다.클 라 이언 트 클래스 의 마지막 출력 을 통 해 클 라 이언 트 com.sun.proxy.$Proxy 0 을 볼 수 있 습 니 다.이것 은 자바 가 실 행 될 때 생 성 된 것 입 니 다.정적 에이전트 의 어 려 운 문 제 를 해결 했다.1.실제 대상 과 대리 류 가 일일이 대응 하고 진실 류 를 증가 하 는 것 도 대리 류 를 증가 해 야 한다.이렇게 하면 유형의 수량 을 신속하게 증가 시 켜 시스템 을 복잡 하 게 만 들 수 있다.왜 이렇게 말 합 니까?프 록 시 클래스 가 인용 하 는 유형 은 Object 이기 때문에 모든 대상 에 마음대로 들 어 갈 수 있 습 니 다.실제 클래스 가 증가 할 때 프 록 시 클래스 는 증가 하지 않 아 도 됩 니 다.new DynamicSubject(object);new 때 들 어 올 대상 을 들 여 보 내 면 됩 니 다.
다음은 프 록 시 뉴 프 록 시 인 스 턴 스(ClassLoader loader,Class[]interfaces, InvocationHandler h); 이 방법의 소스 코드 는 볼 수 있 고 깊이 이해 할 수 있다.
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
。 InvocationHandler 【 】
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
}
);
}
return cons.newInstance(new Object[]{
h
}
);
}
catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
}
catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
}
catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.