AOP之動態代理

weixin_33860722發表於2016-11-19
一.JDK動態代理

使用java.lang.reflect.Proxy動態代理實現,即提取目標物件的介面,然後對介面建立AOP代理

  • 介面
public interface PersonService {
    void update();
    void delete();
}
  • 實現類
public class PersonServiceImpl implements PersonService{
        PersonDAO pdao;
        public void setPdao(PersonDAO pdao){
            this.pdao = pdao;
        }
        /***
         * 這些操作,每個service類都要寫,維護麻煩
         */
        @Override
        public void delete(){
            //是否登入
            //是否有許可權
            //寫日誌
            //事務開始
            pdao.find();
            System.out.println("真正的刪除");
        }
        @Override
        public void update() {
            // TODO Auto-generated method stub
            pdao.find();
            System.out.println("真正的修改");
        }
}
  • JDK動態代理
//jdk提供的動態代理
public class JDKDyncProcyFactory implements InvocationHandler{
    Object target;
    //返回: 代理物件;引數:目標物件(被代理物件)
    public Object createProxyInstance(Object target){
        this.target = target;
        //1.目標物件的類載入器,2.目標物件實現的介面,3.回撥方法(日誌等),這個類實現InvocationHandler藉口,傳this
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
    }
    @Override
    //1.傳進來的代理物件,2.回撥的方法,3.方法的引數
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("日誌開始....");
        //真正的呼叫,反射
        Object result = method.invoke(target, args);
        System.out.println("日誌結束....");
        return result;
    }

}

  • 測試
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService service = (PersonService) ctx.getBean("personService");
//JDK動態代理
JDKDyncProcyFactory factory = new JDKDyncProcyFactory();
PersonService ps = (PersonService) factory.createProxyInstance(service);//返回的代理物件
ps.delete();
二.Cglib代理

CGLIB代理不僅能進行介面代理,也能進行類代理,CGLIB代理需要注意以下問題:
不能通知final方法,因為final方法不能被覆蓋(CGLIB通過生成子類來建立代理)。
會產生兩次構造器呼叫,第一次是目標類的構造器呼叫,第二次是CGLIB生成的代理類的構造器呼叫。如果需要CGLIB代理方法,請確保兩次構造器呼叫不影響應用

  • 介面和實現類同上
  • Cglib代理類
//使用cglib生產動態代理
public class CglibDyncProxFactor {
    public Object createProxyInstance(final Object target){
        Enhancer enhancer = new Enhancer();
        //指定目標物件作為代理物件的父類
        enhancer.setSuperclass(target.getClass());
        Callback callback = new MethodInterceptor() {
            @Override
            public Object intercept(Object arg0, Method arg1, Object[] args,
                    MethodProxy methodProxy) throws Throwable {
                // TODO Auto-generated method stub
                Object result;
                System.out.println("log begin.....");
                result = methodProxy.invoke(target,args);
                System.out.println("log end......");
                return result;
            }
        };
        //定義回撥方法
        enhancer.setCallback(callback);
        //建立代理物件並返回
        return enhancer.create();
        
    }
  • 測試
       //cglih動態代理
        CglibDyncProxFactor factory = new CglibDyncProxFactor();
        PersonService ps = (PersonService) factory.createProxyInstance(service);
        ps.delete();

Spring AOP預設首先使用JDK動態代理來代理目標物件,如果目標物件沒有實現任何介面將使用CGLIB代理

相關文章