zoukankan      html  css  js  c++  java
  • java 的三种代理模式

    (一)https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247485265&idx=1&sn=0ea1fe4257cb963d24829f69bb6a32da&chksm=ebd6387ddca1b16b87f12f50b24b239bed93e0e49f243ec560e2c83156ff5ceefe0a2b2e96fc&mpshare=1&scene=1&srcid=0427wPQP4tYUBtlGH5l1JR9i&key=c44bed40495664a4adac9e43d1f05551d8a4f754cb59ce155cd03562861b122f33144ac9d8403e70841b6302eb1f140b592c78f18e0454b0ee34a2ca8276efd12dbd8e67c6c51b455a6ebd0250532b8e&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=zTFOqug6RXGHRQVhLFV5xM2VvZe0nSmsXV1%2Fys3HrXZVPSKfgf3TVZ7FuYVWc0LA



    1. 静态代理

    public class UserDaoProxy implements IUserDao {
    
        private IUserDao target;
        public UserDaoProxy(IUserDao target){
            this.target = target;
        }
    
        @Override
        public void save() {
            System.out.println("开始事务static");
            target.save();//执行目标对象的方法
            System.out.println("提交事务static");
        }
    }


    2. 动态代理

    public class ProxyFactory implements InvocationHandler {
        //维护一个目标对象
        private Object target;
        public ProxyFactory(Object target){
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("开始事务jdk");
            Object returnValue = method.invoke(target, args);
            System.out.println("提交事务jdk");
            return returnValue;
        }
    
        //给目标对象生成代理对象
        public Object getProxyInstance(){
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
    }


    一个被代理对象,一个invoke改写埋点,一个创建代理对象


            // 目标对象
            IUserDao target = new UserDao();
    
            // 给目标对象,创建代理对象
            IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
    
            // 执行方法   【代理对象】
            proxy.save();
    
        }


    3. cglib

    public class ProxyFactory implements MethodInterceptor {
        //维护目标对象
        private Object target;
    
        public ProxyFactory(Object target) {
            this.target = target;
        }
    
        //给目标对象创建一个代理对象
        public Object getProxyInstance(){
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(target.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.创建子类(代理对象)
            return en.create();
    
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("开始事务cglib");
    
            //执行目标对象的方法
            Object returnValue = method.invoke(target, args);
    
            System.out.println("提交事务cglib");
    
            return returnValue;
        }
    }
    与jdk相同,

    一个被代理对象,一个invoke改写埋点,一个创建代理对象


    
    
            //目标对象
            UserDao target = new UserDao();
    
            //代理对象
            UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
    
            //执行代理对象的方法
            proxy.save();



    (二)https://blog.csdn.net/tanga842428/article/details/52716875

    Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    如何强制使用CGLIB实现AOP?
     (1)添加CGLIB库,SPRING_HOME/cglib/*.jar
     (2)在spring配置文件中加入
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    JDK动态代理和CGLIB字节码生成的区别?
     (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
     (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
       因为是继承,所以该类或方法最好不要声明成final 



    JDK代理是不需要依赖第三方的库,只要JDK环境就可以进行代理,它有几个要求
    * 实现InvocationHandler 
    * 使用Proxy.newProxyInstance产生代理对象
    * 被代理的对象必须要实现接口

    使用JDK动态代理,目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象。


    CGLib 必须依赖于CGLib的类库,
    Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型针对接口编程的环境下推荐使用JDK的代理。从执行效率上看,Cglib动态代理效率较高。在Hibernate中的拦截器其实现考虑到不需要其他接口的条件Hibernate中的相关代理采用的是CGLib来执行


    个人总结:

    jdk方式,实现InvocationHandler接口,使用Proxy,基于反射、动态编译 为实现某接口的类创建代理类

    cglib方式,基于字节码,生成子类改写方法,方法不能为final



    此外有一个2层jdk动态代理例子:

    http://www.cnblogs.com/jiangyi-uestc/p/5755133.html


    JDK的代理方式主要就是通过反射跟动态编译来实现的,主要搭配InvocationHandler和Proxy来实现,下面的例子中使用了两层代理(即代理上加了一层代理)。

     

    二、实例

    1. 公共接口

    复制代码
    1 package com.tgb.proxy;
    2 
    3 public interface UserMgr {
    4 
    5     void addUser();
    6     void delUser();
    7     
    8 }
    复制代码

     

    2. 实现类

    复制代码
     1 package com.tgb.proxy;
     2 
     3 public class UserMgrImpl implements UserMgr {
     4 
     5     @Override
     6     public void addUser() {
     7         System.out.println("添加用户....");
     8     }
     9 
    10     @Override
    11     public void delUser() {
    12         System.out.println("删除用户.....");
    13     }
    14 
    15 }
    复制代码

     

    3. TransactionHandler(InvocationHandler的实现)

    复制代码
     1 package com.tgb.proxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 
     6 public class TransactionHandler implements InvocationHandler {
     7 
     8     private Object target;
     9     
    10     public TransactionHandler(Object target){
    11         super();
    12         this.target = target;
    13     }
    14 
    15     @Override
    16     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    17         
    18         System.out.println("开启事务...");
    19         
    20         method.invoke(target);
    21         
    22         System.out.println("提交事务...");
    23         
    24         return null;
    25     }
    26     
    27 
    28 }
    复制代码

     

    4. TimeHandler(InvocationHandler的实现)

    复制代码
     1 package com.tgb.proxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.util.Calendar;
     6 
     7 public class TimeHandler implements InvocationHandler {
     8 
     9     private Object target;
    10 
    11     public TimeHandler(Object target) {
    12         super();
    13         this.target = target;
    14     }
    15 
    16     @Override
    17     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    18 
    19         Calendar calendar = Calendar.getInstance();
    20 
    21         System.out.println("start time:" + calendar.get(Calendar.HOUR_OF_DAY));
    22 
    23         method.invoke(target);
    24 
    25         System.out.println("end time:" + calendar.get(Calendar.HOUR_OF_DAY));
    26 
    27         return null;
    28     }
    29 
    30 }
    复制代码

     

    5. 测试类

    复制代码
     1 package com.tgb.proxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Proxy;
     5 
     6 public class Client {
     7 
     8     public static void main(String[] args) {
     9 
    10         UserMgr userMgr = new UserMgrImpl();
    11 
    12         // 1.第一层代理----------通过动态代理,添加事务处理
    13         InvocationHandler handler = new TransactionHandler(userMgr);
    14         UserMgr userMgrProxy = (UserMgr) Proxy.newProxyInstance(userMgr.getClass().getClassLoader(),
    15                 userMgr.getClass().getInterfaces(), handler);
    16 
    17         // 2.第二层代理----------通过动态代理,添加时间处理
    18         InvocationHandler handler2 = new TimeHandler(userMgrProxy);
    19         UserMgr userMgrProxy2 = (UserMgr) Proxy.newProxyInstance(userMgrProxy.getClass().getClassLoader(),
    20                 userMgrProxy.getClass().getInterfaces(), handler2);
    21 
    22         userMgrProxy2.addUser();
    23 
    24         System.out.println("========================================");
    25 
    26         userMgrProxy2.delUser();
    27 
    28     }
    29 }
    复制代码

     

    输出结果:

    复制代码
    start time:Tue Aug 09 23:54:54 CST 2016
    开启事务...
    添加用户....
    提交事务...
    end time:Tue Aug 09 23:54:54 CST 2016
    ========================================
    start time:Tue Aug 09 23:54:54 CST 2016
    开启事务...
    删除用户.....
    提交事务...
    end time:Tue Aug 09 23:54:54 CST 2016
    复制代码

  • 相关阅读:
    2020软件工程第一次个人编程作业
    2020软件工程第一次作业
    软件实践个人总结
    2020软件工程第四次编程作业-实验家族树
    2020软件工程个人编程作业
    软工实践个人总结
    2020软件工程结对编程之实验室程序实现
    2020软件工程第一次个人编程作业
    软工作业
    机器学习第四章笔记
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106587.html
Copyright © 2011-2022 走看看