JAVAダイナミックエージェント(JDKとCGLIB)


JAVAの動的エージェントモードエージェントモードはよく使われるjava設計モードであり、エージェントクラスは依頼クラスと同じインタフェースを持つことを特徴とし、エージェントクラスは主に依頼クラスのためにメッセージを前処理し、メッセージをフィルタリングし、メッセージを依頼クラスに転送し、事後処理メッセージなどを担当する.エージェントクラスと委任クラスの間には通常関連関係があり、1つのエージェントクラスのオブジェクトと1つの委任クラスのオブジェクトが関連しており、エージェントクラスのオブジェクト自体はサービスを実装するのではなく、委任クラスのオブジェクトの関連メソッドを呼び出すことで、特定のサービスを提供します.エージェントの作成時期によって、エージェントクラスは2つに分けることができます.静的エージェント:プログラマによって作成または特定のツールによってソースコードが自動的に生成され、コンパイルされます.プログラムの実行前にエージェントクラスの.classファイルはすでに存在します.動的エージェント:プログラムの実行時に、反射メカニズムを用いて動的に作成されます. 
 
まず静的エージェントを見てみましょう:1、Count.java 
package net.battier.dao;  

  

/** 

 *          

 *  

 * @author Administrator 

 *  

 */  

public interface Count {  

    //         

    public void queryCount();  

  

    //         

    public void updateCount();  

  

}  


  
2、CountImpl.java 
package net.battier.dao.impl;  

  

import net.battier.dao.Count;  

  

/** 

 *    (      ) 

 *  

 * @author Administrator 

 *  

 */  

public class CountImpl implements Count {  

  

    @Override  

    public void queryCount() {  

        System.out.println("      ...");  

  

    }  

  

    @Override  

    public void updateCount() {  

        System.out.println("      ...");  

  

    }  

  

}  

  

、CountProxy.java  

package net.battier.dao.impl;  

  

import net.battier.dao.Count;  

  

/** 

 *        (  CountImpl   ) 

 *  

 * @author Administrator 

 *  

 */  

public class CountProxy implements Count {  

    private CountImpl countImpl;  

  

    /** 

     *         

     *  

     * @param countImpl 

     */  

    public CountProxy(CountImpl countImpl) {  

        this.countImpl = countImpl;  

    }  

  

    @Override  

    public void queryCount() {  

        System.out.println("      ");  

        //         ;  

        countImpl.queryCount();  

        System.out.println("      ");  

    }  

  

    @Override  

    public void updateCount() {  

        System.out.println("      ");  

        //         ;  

        countImpl.updateCount();  

        System.out.println("      ");  

  

    }  

  

}  


  
 
3、TestCount.java 
package net.battier.test;  

  

import net.battier.dao.impl.CountImpl;  

import net.battier.dao.impl.CountProxy;  

  

/** 

 *  Count  

 *  

 * @author Administrator 

 *  

 */  

public class TestCount {  

    public static void main(String[] args) {  

        CountImpl countImpl = new CountImpl();  

        CountProxy countProxy = new CountProxy(countImpl);  

        countProxy.updateCount();  

        countProxy.queryCount();  

  

    }  

}  


  
 
コードを観察すると、各エージェントクラスは1つのインタフェースにしかサービスできないことがわかります.これにより、プログラム開発では必然的に多くのエージェントが生成されます.また、すべてのエージェント操作は呼び出しの方法が異なる以外は、他の操作は同じであり、この場合、世代コードが繰り返されるに違いありません.この問題を解決する最善の方法は、1つのエージェントクラスですべてのエージェント機能を完了できるようにすることです.この場合、動的エージェントを使用して完了する必要があります.動的エージェント:JDK動的エージェントにはクラスとインタフェースが含まれています:InvocationHandlerインタフェース:public interface InvocationHandler{public Object invoke(Object proxy,Method,Object[args])throws Throwable;}パラメータの説明:Object proxy:エージェントされるオブジェクトを指します.Method method:呼び出すメソッドObject[]args:メソッド呼び出しに必要なパラメータ
InvocationHandlerインタフェースのサブクラスをエージェントの最終操作クラスとして想像し,ProxySubjectを置き換えることができる. 
Proxyクラス:Proxyクラスはエージェントを専門とする操作クラスであり、1つ以上のインタフェースに対して動的に実装クラスを生成することができます.これには、public static Object newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)throws I llegalArgumentExceptionパラメータの説明:ClassLoader loader:クラスローダClass[]interfaces:すべてのインタフェースを取得InvocationHandler h:InvocationHandlerインタフェースのサブクラスインスタンスを取得する
Ps:Proxyクラス内のクラスローダのnewProxyInstance()メソッドにはClassLoaderクラスのインスタンスが必要です.ClassLoaderは実際にはクラスローダに対応しています.Javaには主に3種類のローダがあります.Booststrap ClassLoader:このローダはC++で記述されています.一般開発では見られません.Extendsion ClassLoader:拡張クラスのロードに使用されます.一般的にはjrelibextディレクトリのクラスに対応しています.AppClassLoader:(デフォルト)classpathで指定されたクラスをロードし、最もよく使用されるのはローダです. 
動的エージェントは静的エージェントクラスと対照的に動的エージェントクラスであり,動的エージェントクラスのバイトコードはプログラム実行時にJava反射メカニズムによって動的に生成され,プログラマが手動でソースコードを記述する必要はない.動的エージェントクラスはプログラミング作業を簡素化するだけでなく、Java反射メカニズムが任意のタイプの動的エージェントクラスを生成できるため、ソフトウェアシステムの拡張性を向上させる.java.lang.reflectパッケージのProxyクラスとInvocationHandlerインタフェースは、動的エージェントクラスを生成する能力を提供します. 
動的エージェントの例:1、BookFacade.java 
package net.battier.dao;  

  

public interface BookFacade {  

    public void addBook();  

}  


  
 
2、BookFacadeImpl.java 
package net.battier.dao.impl;  

  

import net.battier.dao.BookFacade;  

  

public class BookFacadeImpl implements BookFacade {  

  

    @Override  

    public void addBook() {  

        System.out.println("      。。。");  

    }  

  

}  

  

、BookFacadeProxy.java  

  

package net.battier.proxy;  

  

import java.lang.reflect.InvocationHandler;  

import java.lang.reflect.Method;  

import java.lang.reflect.Proxy;  

  

/** 

 * JDK        

 *  

 * @author student 

 *  

 */  

public class BookFacadeProxy implements InvocationHandler {  

    private Object target;  

    /** 

     *                

     * @param target 

     * @return 

     */  

    public Object bind(Object target) {  

        this.target = target;  

        //        

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  

                target.getClass().getInterfaces(), this);   //     (      ,cglib       )  

    }  

  

    @Override  

    /** 

     *      

     */  

    public Object invoke(Object proxy, Method method, Object[] args)  

            throws Throwable {  

        Object result=null;  

        System.out.println("    ");  

        //      

        result=method.invoke(target, args);  

        System.out.println("    ");  

        return result;  

    }  

  

}  


  
 
3、TestProxy.java 
package net.battier.test;  

  

import net.battier.dao.BookFacade;  

import net.battier.dao.impl.BookFacadeImpl;  

import net.battier.proxy.BookFacadeProxy;  

  

public class TestProxy {  

  

    public static void main(String[] args) {  

        BookFacadeProxy proxy = new BookFacadeProxy();  

        BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  

        bookProxy.addBook();  

    }  

  

}  


  
 
しかし,JDKの動的エージェントはインタフェースに依存して実現され,クラスによってはインタフェースが実装されていない場合,JDKエージェントは使用できないため,cglib動的エージェントが使用される. 
Cglib動的エージェントJDKの動的エージェントメカニズムはエージェントがインタフェースを実現したクラスのみをエージェントすることができ、インタフェースを実現できないクラスはJDKの動的エージェントを実現することができず、cglibはクラスに対してエージェントを実現し、彼の原理は指定した目標クラスに対してサブクラスを生成し、その中国側法をカバーして強化を実現することであるが、継承を採用しているため、だからfinal修飾のクラスをエージェントすることはできません.例1、BookFacadeCglib.java 
package net.battier.dao;  

  

public interface BookFacade {  

    public void addBook();  

}  


  
 
2、BookCadeImpl1.java 
package net.battier.dao.impl;  

  

/** 

 *               

 *  

 * @author student 

 *  

 */  

public class BookFacadeImpl1 {  

    public void addBook() {  

        System.out.println("         ...");  

    }  

}  


  
3、BookFacadeProxy.java 
package net.battier.proxy;  

  

import java.lang.reflect.Method;  

  

import net.sf.cglib.proxy.Enhancer;  

import net.sf.cglib.proxy.MethodInterceptor;  

import net.sf.cglib.proxy.MethodProxy;  

  

/** 

 *   cglib     

 *  

 * @author student 

 *  

 */  

public class BookFacadeCglib implements MethodInterceptor {  

    private Object target;  

  

    /** 

     *        

     *  

     * @param target 

     * @return 

     */  

    public Object getInstance(Object target) {  

        this.target = target;  

        Enhancer enhancer = new Enhancer();  

        enhancer.setSuperclass(this.target.getClass());  

        //       

        enhancer.setCallback(this);  

        //         

        return enhancer.create();  

    }  

  

    @Override  

    //       

    public Object intercept(Object obj, Method method, Object[] args,  

            MethodProxy proxy) throws Throwable {  

        System.out.println("    ");  

        proxy.invokeSuper(obj, args);  

        System.out.println("    ");  

        return null;  

    }  

}  


  
4、TestCglib.java 
package net.battier.test;  

  

import net.battier.dao.impl.BookFacadeImpl1;  

import net.battier.proxy.BookFacadeCglib;  

  

public class TestCglib {  

      

    public static void main(String[] args) {  

        BookFacadeCglib cglib=new BookFacadeCglib();  

        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  

        bookCglib.addBook();  

    }  

}