자바 동적 에이전트 원리 상세 설명
Spring 을 공부 할 때 우 리 는 Spring 이 주로 두 가지 사상 을 가지 고 있다 는 것 을 알 고 있다. 하 나 는 IoC 이 고 다른 하 나 는 AOP 이다. IoC 에 대한 의존 주입 은 더 말 할 필요 가 없다. Spring 의 핵심 AOP 에 있어 우 리 는 AOP 를 통 해 우리 의 기능 을 만족 시 키 는 방법 을 알 아야 할 뿐만 아니 라 그 밑바닥 이 어떤 원리 인지 배 워 야 한다.한편, AOP 의 원 리 는 바로 자바 의 동적 대리 체제 이기 때문에 본 수필 은 자바 의 동적 체 제 를 돌 이 켜 보 는 것 이다.
먼저 질문 하나 하 겠 습 니 다. 왜 동적 대리 가 필요 합 니까?코드 혼란: 점점 더 많은 비 업무 수요 (로그 와 검증 등) 가 가입 한 후에 기 존의 업무 방법 이 급 격 히 팽창 했다.모든 방법 은 핵심 논 리 를 처리 하 는 동시에 다른 여러 가지 관심 사 를 동시에 고려 해 야 한다.예 를 들 어 방법 을 새로 추가 할 때마다 로그 와 검증 을 계속 써 야 합 니 다.코드 분산: 로그 수 요 를 예 로 들 면 이 단일 수 요 를 만족 시 키 기 위해 여러 모듈 (방법) 에서 같은 로그 코드 를 여러 번 반복 해 야 합 니 다.로그 수요 가 바 뀌 면 모든 모듈 을 수정 해 야 합 니 다.예 를 들 어 현재 이런 방법 에 방법 명 이 표시 되 어 있 으 면 모든 방법 을 하나씩 고 쳐 야 한다.
기 제 는 자바 의 동적 프 록 시 체제 에서 두 가지 중요 한 유형 이나 인터페이스 가 있 는데 하 나 는 InvocationHandler (Interface) 이 고 다른 하 나 는 Proxy (Class) 이다. 이런 유형 과 인 터 페 이 스 는 우리 의 동적 프 록 시 를 실현 하 는 데 필요 한 것 이다.우선 자바 의 API 도움말 문서 가 이 두 가지 유형 에 대해 어떻게 설명 하 는 지 살 펴 보 겠 습 니 다.
InvocationHandler:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler. 모든 동적 프 록 시 클래스 는 InocationHandler 라 는 인 터 페 이 스 를 실현 해 야 하 며, 모든 프 록 시 클래스 의 인 스 턴 스 는 하나의 handler 와 연결 되 어 있 습 니 다.우리 가 대리 대상 을 통 해 하나의 방법 을 호출 할 때 이 방법의 호출 은 Invocation Handler 라 는 인터페이스의 invoke 방법 으로 호출 된다.Invocation Handler 라 는 인터페이스의 유일한 방법 인 invoke 방법 을 살 펴 보 겠 습 니 다.
Object invoke (Object proxy, Method method, Object [] args) throws Throwable 우 리 는 이 방법 이 모두 세 개의 인 자 를 받 아들 이 는 것 을 보 았 습 니 다. 그러면 이 세 개의 인 자 는 각각 무엇 을 대표 합 니까?
Object invoke (Object proxy, Method method, Object [] args) throws Throwable proxy: - 우리 가 대리 하 는 그 실제 대상 method 를 말 합 니 다. - 우리 가 실제 대상 을 호출 하려 는 어떤 방법 을 말 합 니 다. Method 대상 args: - 실제 대상 을 호출 할 때 받 아들 이 는 매개 변 수 를 말 합 니 다. 잘 모 르 면...다음 인 스 턴 스 를 통 해 이 몇 개의 매개 변 수 를 더욱 깊이 설명 할 것 입 니 다.
다음은 프 록 시 클래스 를 살 펴 보 겠 습 니 다.
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 프 록 시 같은 역할 은 프 록 시 대상 의 클래스 를 동적 으로 만 드 는 데 많은 방법 을 제공 하지만 우리 가 가장 많이 사용 하 는 것 은 new Proxy Instance 라 는 방법 입 니 다.
public static Object newProxy Instance (ClassLoader loader, Class > [] interfaces, InvocationHandler h) throws IllegalArgument Exception Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. 이 방법의 역할 은 동적 인 프 록 시 대상 을 얻 는 것 입 니 다.세 개의 매개 변 수 를 받 습 니 다. 이 세 개의 매개 변수 가 대표 하 는 의 미 를 살 펴 보 겠 습 니 다.
public static Object newProxyInstance (ClassLoader loader, Class > [] interfaces, Invocation Handler h) throws IllegalArgument Exception loader: 하나의 ClassLoader 대상 은 생 성 된 프 록 시 대상 에 대해 인 터 페 이 스 를 불 러 오 는 것 을 정의 합 니 다. 하나의 Interface 대상 의 배열,내 가 대리 가 필요 한 대상 에 게 어떤 인 터 페 이 스 를 제공 할 것 인 지 를 나타 낸다. 만약 에 내 가 인 터 페 이 스 를 제공 하면 이 대리 대상 은 이 인터페이스 (다 중) 를 실현 했다 고 주장 한다. 그러면 나 는 이 인터페이스 중의 방법 을 호출 할 수 있다. h: Invocation Handler 대상 은 내 가 이 동적 대리 대상 이 호출 방법 을 사용 할 때어떤 Invocation Handler 대상 과 연결 되 는 지 소개 하 겠 습 니 다. 이 두 인터페이스 (클래스) 를 소개 한 후에 우 리 는 하나의 인 스 턴 스 를 통 해 우리 의 동적 에이전트 모델 이 어떤 지 보 겠 습 니 다.
먼저 우 리 는 Subject 형식의 인 터 페 이 스 를 정의 하여 두 가지 방법 을 설명 했다.
public interface Subject { public void rent();
public void hello(String str);
} 이어서 이 인 터 페 이 스 를 실현 하 는 클래스 를 정 의 했 습 니 다. 이 클래스 가 바로 우리 의 실제 대상 입 니 다. RealSubject 클래스:
public class RealSubject implements Subject { @Override public void rent() { System.out.println(“I want to rent my house”); }
@Override
public void hello(String str)
{
System.out.println("hello: " + str);
}
} 다음 단계 에 우 리 는 동적 프 록 시 클래스 를 정의 해 야 합 니 다. 앞에서 말 했 듯 이 모든 동적 프 록 시 클래스 는 Invocation Handler 라 는 인 터 페 이 스 를 실현 해 야 합 니 다. 따라서 우리 의 이 동적 프 록 시 클래스 도 예외 가 아 닙 니 다.
public class DynamicProxy implements Invocation Handler {/ 이것 이 바로 우리 가 대리 할 실제 대상 private Object subject 입 니 다.
// ,
public DynamicProxy(Object subject)
{
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
//
System.out.println("before rent house");
System.out.println("Method:" + method);
// , handler invoke
method.invoke(subject, args);
//
System.out.println("after rent house");
return null;
}
} 마지막 으로 우리 클 라 이언 트 클래스 를 보 세 요:
public class Client {public static void main (String [] args) {/ / 우리 가 대리 할 실제 대상 Subject realSubject = new RealSubject ();
// , ,
InvocationHandler handler = new DynamicProxy(realSubject);
/*
* Proxy newProxyInstance ,
* handler.getClass().getClassLoader(), handler ClassLoader
* realSubject.getClass().getInterfaces(), , ,
* handler, InvocationHandler
*/
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
} 콘 솔 의 출력 을 살 펴 보 겠 습 니 다.
$Proxy0
before rent house Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent() I want to rent my house after rent house
before rent house 방법: public abstract void com. xiaoluo. dynamicproxy. Subject. hello (java. lang. String) hello: world after rent house 먼저 $Proxy 0 을 보 겠 습 니 다. 이 물건 은 System. out. println (subject. getClass (). getName ()) 입 니 다.; 이 문 구 는 인쇄 되 어 있 습 니 다. 그런데 왜 우리 가 돌아 온 이 대리 대상 의 유형 명 은 이 렇 습 니까?
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); 돌아 오 는 이 프 록 시 대상 이 Subject 형식의 대상 이 라 고 생각 했 거나 Invocation Handler 의 대상 이 라 고 생각 했 을 수도 있 습 니 다. 결 과 는 그렇지 않 았 습 니 다. 우선 우리 가 왜 Subject 형식의 대상 으로 바 꿀 수 있 는 지 설명 하 겠 습 니 다. 그 이 유 는 new Proxy Instance 라 는 방법의 두 번 째 매개 변수 에서 우 리 는 이 프 록 시 대상 에 게 어떤 인 터 페 이 스 를 제공 하 였 습 니까?이 프 록 시 대상 은 이 인 터 페 이 스 를 실현 할 수 있 습 니 다. 이때 우 리 는 당연히 이 프 록 시 대상 의 강제 유형 을 이 인터페이스 중의 임의의 것 으로 바 꿀 수 있 습 니 다. 여기 의 인 터 페 이 스 는 Subject 유형 이기 때문에 Subject 유형 으로 바 꿀 수 있 습 니 다.
또한 프 록 시. new Proxy Instance 를 통 해 만 든 프 록 시 대상 은 jvm 이 실 행 될 때 동적 으로 생 성 된 대상 임 을 기억 해 야 합 니 다. 이것 은 우리 의 Invocation Handler 형식 도 아니 고 우리 가 정의 하 는 인터페이스 유형 도 아니 라 동적 으로 생 성 된 대상 이 며 이름 을 짓 는 방식 은 모두 이러한 형식 입 니 다. $로 시작 하고 proxy 를 중심 으로 마지막 으로하나의 숫자 는 대상 의 레이 블 을 나타 낸다.
이어서 이 두 마디 를 보도 록 하 겠 습 니 다.
subject.rent(); subject.hello(“world”); 이것 은 프 록 시 대상 을 통 해 실 현 된 인터페이스 에서 호출 하 는 방법 입 니 다. 이 때 프로그램 은 이 프 록 시 대상 과 연 결 된 handler 의 invoke 방법 으로 전 환 됩 니 다. 그리고 우리 의 이 handler 대상 은 RealSubject 형식의 인 자 를 받 아 내 가 대리 하고 자 하 는 것 이 바로 이 실제 대상 임 을 나타 내 므 로 이때 handler 에서 호출 됩 니 다.의 invoke 방법 으로 실행:
public Object invoke (Object object, Method method, Object [] args) throws Throwable {/ / 프 록 시 실제 대상 앞에서 우 리 는 자신의 조작 System. out. println ("before rent house") 을 추가 할 수 있 습 니 다.
System.out.println("Method:" + method);
// , handler invoke
method.invoke(subject, args);
//
System.out.println("after rent house");
return null;
} 우 리 는 진정 으로 대리 대상 을 통 해 실제 대상 을 호출 하 는 방법 을 볼 때, 우 리 는 이 방법 전후 에 자신의 조작 을 추가 할 수 있 으 며, 동시에 우 리 는 우리 의 이 method 대상 이 이렇다 는 것 을 볼 수 있다.
public abstract void com.xiaoluo.dynamicproxy.Subject.rent()
public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)바로 우리 의 Subject 인터페이스 에 있 는 두 가지 방법 입 니 다. 이것 은 제 가 대리 대상 을 통 해 방법 을 호출 할 때 실제 적 으로 관련 된 handler 대상 의 invoke 방법 에서 호출 을 의뢰 하 는 것 입 니 다. 자신 이 진실 하 게 호출 하 는 것 이 아니 라 대리 적 인 방식 으로 호출 한 것 임 을 증명 합 니 다.
이것 이 바로 우리 의 자바 동적 에이전트 입 니 다.https://blog.csdn.net/Dream_Weave/article/details/84183247