java中の静的エージェントと動的エージェントを深く解析する。

9086 ワード

java符号化ではしばしばプロキシが使用され、プロキシは静的エージェントと動的エージェントに分類される。動的エージェントは、spring中のaopを実現することができる。
一、スタティックエージェント:プログラムが実行される前に、プログラマーは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();
    }
}
二、ダイナミックエージェント:実際のコードはコンパイル中に生成されず、運転中に反射機構を使って動的に生成される。
エージェントインターフェース
 
  
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;
    }
}
テストクラス
 
  
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();
    }
}
出力結果:
before-----------------------------
AService add>>>>>>>>>>>
after----------------------
before-----------------------------
AService udate>>>>>>>>>
after----------------------
上記のフラグのステートメントは、プロキシクラスのキーコードを生成し、Serviceインターフェースに該当するプロキシオブジェクトを生成することができます。newProxyInstanceという方法は、プロキシのすべてのインターフェースをコード動的に生成されたクラスで実行します。このクラスのすべてのインターフェースの方法はInvocationHandler.invokeを呼び出します。方法
以下では、プロキシオブジェクトの生成をどのように行うかを詳細に説明します。
ProxyのnewProxyInstanceメソッドは、この方法の異常処理文を簡単に見えるように削除しました。
下のpublic static Object newProxInstance(Class Loader loader、  Class>[]interfaces,InvocationHandler h)throws
 
  
    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のget Proxyクラスの方法
 
  
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;
}
ProxyGeneratorのgenerate ProxyClass方法を見て、この方法は最終的にエージェントクラスのバイトコードファイルを生成します。
 
  
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() { 
               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; 
   }
最終的に生成されたプロキシ類はどのようなものですか?
 
  
public final class $Proxy11 extends Proxy implements Service 
{      // , MyInvocationHandler  
    public $Proxy11(InvocationHandler invocationhandler) 
    { 
        super(invocationhandler); 
    } 

    /**
     * add , , MyInvocationHandler invoke
     */ 
    public final void add() 
    { 
        try 
        { 
            // MyInvocationHandler invoke  
            super.h.invoke(this, m3, null); 
            return; 
        } 
        catch(Error _ex) { } 
       catch(Throwable throwable) 
        { 
            throw new UndeclaredThrowableException(throwable); 
        } 
   }