동적 프록시는 실제로 사용자가 지정한 모든 인터페이스를 기반으로 클래스 바이트를 동적으로 생성하는 java.lang.reflect.Proxy 클래스입니다. 이 클래스는 프록시 클래스를 상속하고 사용자가 지정한 모든 인터페이스(매개변수에 전달하는 인터페이스 배열)를 구현합니다. ) ; 그런 다음 지정한 클래스 로더를 사용하여 클래스 바이트를 시스템에 로드하고 마지막으로 해당 클래스의 객체를 생성하고 모든 인터페이스에 해당하는 Method 멤버인 invocationHandler와 같은 객체의 일부 값을 초기화합니다. . 초기화 후 개체는 호출 클라이언트로 반환됩니다. 이러한 방식으로 클라이언트는 모든 인터페이스를 구현하는 프록시 개체를 얻습니다. 예시 분석을 참조하세요.
공용 인터페이스 BusinessProcessor {
공공 무효 프로세스비즈니스();
}
@보수
공공 무효 프로세스비즈니스() {
System.out.println("업무 처리 중....");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
*사업대행업 카테고리
* @author fanshadoop
*
*/
공개 클래스 BusinessProcessorHandler는 InvocationHandler를 구현합니다.
개인 개체 대상 = null;
BusinessProcessorHandler(객체 대상) {
this.target = 대상;
}
공용 객체 호출(객체 프록시, 메소드 메소드, Object[] args)
Throwable {를 던집니다.
시스템아웃
.println("비즈니스를 처리하기 전에 여기서 할 수 있는 작업이 있습니다.");
객체 결과 = method.invoke(target, args);
시스템아웃
.println("업무를 처리한 후 여기서 뭔가를 할 수 있습니다.");
결과 반환;
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
공개 클래스 테스트 {
/**
* @param 인수
*/
공개 정적 무효 메인(String[] args) {
BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler 핸들러 = new BusinessProcessorHandler(bpimpl);
비즈니스프로세서 bp = (비즈니스프로세서) Proxy.newProxyInstance(
bpimpl.getClass().getClassLoader(), bpimpl.getClass()
.getInterfaces(), 핸들러);
bp.processBusiness();
System.out.println(bp.getClass().getName());
printClassDefinition(bp.getClass());
}
공개 정적 문자열 getModifier(int 수정자) {
문자열 결과 = "";
스위치(수정자) {
케이스 수정자.PRIVATE:
결과 = "비공개";
케이스 수정자.PUBLIC:
결과 = "공개";
케이스 수정자.PROTECTED:
결과 = "보호됨";
케이스 수정자.요약:
결과 = "추상";
케이스 수정자.최종:
결과 = "최종";
케이스 수정자.NATIVE:
결과 = "네이티브";
케이스 수정자.STATIC:
결과 = "정적";
케이스 수정자.동기화됨:
결과 = "동기화됨";
케이스 수정자.STRICT:
결과 = "엄격함";
케이스 수정자.TRANSIENT:
결과 = "일시적";
대소문자 수정자.VOLATILE:
결과 = "휘발성";
케이스 수정자.인터페이스:
결과 = "인터페이스";
}
결과 반환;
}
공공 정적 무효 printClassDefinition(클래스 clz) {
String clzModifier = getModifier(clz.getModifiers());
if (clzModifier != null && !clzModifier.equals("")) {
clzModifier = clzModifier + " ";
}
String superClz = clz.getSuperclass().getName();
if (superClz != null && !superClz.equals("")) {
superClz = "확장" + superClz;
}
클래스[] 인터페이스 = clz.getInterfaces();
문자열 inters = "";
for (int i = 0; i < 인터페이스.길이; i++) {
if (i == 0) {
inters += "구현";
}
inters += 인터페이스[i].getName();
}
System.out.println(clzModifier + clz.getName() + " " + superClz + " "
+ 인터);
System.out.println("{");
Field[] fields = clz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
문자열 수정자 = getModifier(fields[i].getModifiers());
if (수정자 != null && !modifier.equals("")) {
수정자 = 수정자 + " ";
}
문자열 fieldName = 필드[i].getName();
문자열 fieldType = 필드[i].getType().getName();
System.out.println(" " + 수정자 + fieldType + " " + fieldName
+ ";");
}
System.out.println();
Method[] 메소드 = clz.getDeclaredMethods();
for (int i = 0; i <methods.length; i++) {
메소드 메소드 = 메소드[i];
문자열 수정자 = getModifier(method.getModifiers());
if (수정자 != null && !modifier.equals("")) {
수정자 = 수정자 + " ";
}
문자열 methodName = method.getName();
클래스 returnClz = method.getReturnType();
문자열 retrunType = returnClz.getName();
Class[] clzs = method.getParameterTypes();
문자열 paraList = "(";
for (int j = 0; j < clzs.length; j++) {
paraList += clzs[j].getName();
if (j != clzs.length - 1) {
paraList += ", ";
}
}
paraList += ")";
clzs = method.getExceptionTypes();
문자열 예외 = "";
for (int j = 0; j < clzs.length; j++) {
if (j == 0) {
예외 += "throws";
}
예외 += clzs[j].getName();
if (j != clzs.length - 1) {
예외 += ", ";
}
}
예외 += ";";
문자열 methodPrototype = 수정자 + retrunType + " " + methodName
+ paraList + 예외;
System.out.println(" " + methodPrototype);
}
System.out.println("}");
}
}
부울 같음(java.lang.Object);
java.lang.String toString();
int hashCode();
무효 프로세스비즈니스();
}
분명히 Proxy.newProxyInstance 메서드는 다음 작업을 수행합니다.
1. 인터페이스에서 인터페이스를 구현하기 위해 전달된 두 번째 매개변수 인터페이스를 기반으로 클래스를 동적으로 생성합니다. 이 예에서는 BusinessProcessor 인터페이스의 processBusiness 메소드입니다. 그리고 Proxy 클래스를 상속하고 hashcode, toString 및 equals와 같은 세 가지 메서드를 다시 작성합니다. 구체적인 구현에 대해서는 ProxyGenerator.generateProxyClass(...)를 참조하십시오. 이 예에서는 $Proxy0 클래스가 생성됩니다.
2. 전달된 첫 번째 매개변수인 classloder를 통해 새로 생성된 클래스를 jvm에 로드합니다. $Proxy0 클래스를 로드하려고 합니다.
3. 세 번째 매개변수를 사용하여 $Proxy0의 $Proxy0(InvocationHandler) 생성자를 호출하여 $Proxy0의 개체를 생성하고, 인터페이스 매개변수를 사용하여 모든 인터페이스 메서드를 순회하고 Method 개체를 생성하여 여러 Method 멤버 변수를 초기화합니다. 물체.
4. $Proxy0의 인스턴스를 클라이언트에 반환합니다.
지금은 괜찮습니다. 클라이언트가 이를 어떻게 조정하는지 살펴보겠습니다. 그러면 명확해질 것입니다.
1. 클라이언트는 $Proxy0의 인스턴스 객체를 가져옵니다. $Proxy0은 BusinessProcessor를 상속하므로 BusinessProcessor로 변환하는 데 문제가 없습니다.
비즈니스프로세서 bp = (비즈니스프로세서)Proxy.newProxyInstance(....);
2.bp.processBusiness();
실제로 호출되는 것은 $Proxy0.processBusiness()이고, $Proxy0.processBusiness()의 구현은 InvocationHandler를 통해 호출 메소드를 호출하는 것입니다!