자바의 정적 에이전트와 동적 에이전트를 깊이 있게 분석하다

자바 인코딩에서 에이전트를 자주 사용하는데 에이전트는 정적 에이전트와 동적 에이전트로 나뉜다.그 중에서 동적 에이전트는spring의 aop을 실현할 수 있다.
1. 정적 에이전트: 프로그램이 실행되기 전에 프로그래머는proxy를 작성하고 컴파일해야 합니다. 즉, 프로그램이 실행되기 전에 에이전트 클래스의 바이트 파일이 생성됩니다.
피프록시류의 공공부류

package staticproxy;
public abstract class BaseClass {
    public abstract void add();
}
피프록시류

package staticproxy;
public class A extends BaseClass {
    public void add() {
        System.out.println("A add !");
    }
}
프록시류

package staticproxy;
public class Proxy {
    BaseClass baseClass;
    public void add() {
        baseClass.add();
    }
    public void setBaseClass(BaseClass baseClass) {
        this.baseClass = baseClass;
    }
    public static void main(String[] args) {
        BaseClass baseClass = new A();
        Proxy proxy = new Proxy();
        proxy.setBaseClass(baseClass);
        proxy.add();
    }
}
2. 동적 프록시: 실제 코드는 컴파일하는 동안 생성되지 않고 운행하는 동안 반사 메커니즘을 활용하여 동적 생성
피프록시 클래스 인터페이스

package jdkproxy;
public interface Service {
    public void add();
    public void update();
}
피프록시 클래스 A

package jdkproxy;
public class AService implements Service {
    public void add() {
        System.out.println("AService add>>>>>>>>>>>>>>>>>>");
    }
    public void update() {
        System.out.println("AService update>>>>>>>>>>>>>>>");
    }
}
피프록시 클래스 B

package jdkproxy;
public class BService implements Service {
    public void add() {
        System.out.println("BService add---------------");
    }
    public void update() {
        System.out.println("BService update---------------");
    }
}
테스트 클래스

package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    MyInvocationHandler() {
        super();
    }
    MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //
        System.out.println("before-----------------------------");
        //
        Object result = method.invoke(target, args);
        //
        System.out.println("after------------------------------");
        return result;
    }
    public Object getTarget() {
        return target;
    }
    public void setTarget(Object target) {
        this.target = target;
    }
}
출력 결과: before---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
그 중에서 상기 빨간색 문장은 프록시 클래스를 만드는 관건적인 코드로 서비스 인터페이스에 부합되는 프록시 대상을 만들 수 있다. newProxy Instance라는 방법은 이런 일을 할 것이다. 그는 당신이 프록시할 모든 인터페이스를 코드가 동적으로 생성된 클래스로 실현할 것이다. 이 클래스의 모든 인터페이스 중의 방법은 InvocationHandler를 호출하는 것으로 다시 쓸 것이다.invoke () 메서드.
다음은 어떻게 대리 대상의 생성을 실현하는지 상세하게 소개한다.
Proxy의 new Proxy Instance 방법, 그 중에서 보기에 편리하도록 이 방법의 이상 처리 문장을 삭제했습니다
다음 public static Object new Proxy Instance(Class Loader loader, Class [] interfaces, Invocation Handlerh)throws

package jdkproxy;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        Service aService = new AService();
        MyInvocationHandler handler = new MyInvocationHandler(aService);
        // Proxy InvocationHandler
        Service aServiceProxy = (Service) Proxy.newProxyInstance(aService
                .getClass().getClassLoader(), aService.getClass()
                .getInterfaces(), handler);
        // aServiceProxyaServiceProxy Service
        aServiceProxy.add();
        System.out.println();
        aServiceProxy.update();
        // B
        // Service bService = new BService();
        // MyInvocationHandler handler = new MyInvocationHandler(bService);
        // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService
        // .getClass().getClassLoader(), bService.getClass()
        // .getInterfaces(), handler);
        // bServiceProxy.add();
        // System.out.println();
        // bServiceProxy.update();
    }
}
Proxy의 getProxy Class 방법

    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException 
    { 
        if (h == null) { 
            throw new NullPointerException(); 
        } 
        //
        Class cl = getProxyClass(loader, interfaces); 
        Constructor cons = cl.getConstructor(constructorParams); 
        // , MyInvocationHandler , MyInvocationHandler invoke , MyInvocationHandler  
        return (Object) cons.newInstance(new Object[] { h }); 
    }  getProxyClass
아래에서 Proxy Generator의generate Proxy Class 방법을 보십시오. 이 방법은 최종적으로 프록시 클래스의 바이트 파일을 생성합니다.

public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
{
    // 、 、 ,
    byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(proxyName, interfaces);
    proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
    proxyClasses.put(proxyClass, null);
    return proxyClass;
}
그러면 최종적으로 생성된 프록시 클래스는 어떤 모습일까요?다음과 같다(equals,hashcode,toString 등 방법을 생략하고 구조 함수와add방법만 보여준다):

public static byte[] generateProxyClass(final String name, Class[] interfaces) 
   { 
       ProxyGenerator gen = new ProxyGenerator(name, interfaces); 
    //
       final byte[] classFile = gen.generateClassFile(); 
    // saveGeneratedFiles true,  
       if (saveGeneratedFiles) { 
           java.security.AccessController.doPrivileged( 
           new java.security.PrivilegedAction<Void>() { 
               public Void run() { 
                   try { 
                       FileOutputStream file = 
                           new FileOutputStream(dotToSlash(name) + ".class"); 
                       file.write(classFile); 
                       file.close(); 
                       return null; 
                   } catch (IOException e) { 
                       throw new InternalError( 
                           "I/O exception saving generated file: " + e); 
                   } 
               } 
           }); 
       } 
    //  
       return classFile; 
   }

좋은 웹페이지 즐겨찾기