• 理解三种代理模式


    一、代理模式

      代理,顾名思义可以简单理解为代为管理,代理模式就是为其他对象提供额外服务,控制访问(前置处理),或做善后处理(后置处理)。有了代理之后,可以在原来功能的基础上由代理完成另外一部分事情

      常见的代理模式有:

        • 静态代理:这种代理模式需要代理对象和目标对象实现相同的接口。可以在不修改目标对象的基础上扩展功能。
          • 缺点:静态代理由于需要和目标对象实现相同的接口,当代理对象变多的时候代理类就会跟着增加,而且一旦更改了接口,那么目标对象和代理对象都要同时做出调整,不方便管理。
        • 动态代理:代理对象不需要实现目标对象接口,通过JAVA的API动态生成目标对象的代理对象。Proxy.newProxyInstance(。。。),其中有三个参数:
          • ClassLoader loader:目标对象的类加载器
          • Class<?>[] interfaces:目标对象的接口类型
          • InvocationHandler h:事件处理函数,实现对目标对象的操作。
        • CGLIB动态代理:也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
          • JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
          • Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
          • Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.

    二、静态代理(需要接口)

      静态代理需要目标对象和代理对象实现相同的接口:

      UserDaoInterface接口类:

    1 public interface UserDaoInterface {
    2     public void save();
    3 }

      目标对象:

    1 public class UserDao implements UserDaoInterface {
    2     public void save() {
    3         System.out.println("保存用户信息中。。。。");
    4     }
    5 }

      代理对象:

     1 /**
     2  * 代理对象,和目标对象实现相同接口
     3  */
     4 public class UserDaoProxy implements UserDaoInterface {
     5     private UserDaoInterface userDao;
     6 
     7     public UserDaoProxy(UserDaoInterface userDao) {
     8         this.userDao = userDao;
     9     }
    10 
    11     public void save() {
    12         System.out.println("开始保存");
    13         userDao.save();
    14         System.out.println("保存成功");
    15     }
    16 }

      测试类:

    1 public class Test {
    2     @org.junit.jupiter.api.Test
    3     public void testDemo(){
    4         System.out.println("静态代理");
    5         //获取对象
    6         UserDaoInterface userDao = new UserDaoProxy(new UserDao());
    7         userDao.save();
    8     }
    9 }

      实现结果:

      如果要增加接口的方法,目标对象和代理对象类都需要修改。

    三、动态代理(需要接口)

      动态代理,代理对象无需刻意实现目标对象接口。

      接口类

    1 public interface UserDaoInterface {
    2     public void save();
    3 }

      目标类

    1 public class UserDao implements UserDaoInterface {
    2     public void save() {
    3         System.out.println("保存用户信息中。。。。");
    4     }
    5 }

      代理类(动态代理,代理类没有实现和目标对象一样的接口 而是通过javaAPI在内存中为我们动态创建了一个代理对象)

     1 /**
     2  * 代理工厂类
     3  */
     4 public class ProxyFactory {
     5     private Object obj;
     6 
     7     public ProxyFactory(Object obj) {
     8         this.obj = obj;
     9     }
    10 
    11     public Object getInstance(){
    12         return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    13             obj.getClass().getInterfaces(),
    14             new InvocationHandler() {
    15                 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    16                     System.out.println("开始保存");
    17                     Object returnObject = method.invoke(obj,args);
    18                     System.out.println("保存成功");
    19                     return returnObject;
    20                 }
    21             });
    22     }
    23 }

      测试类:

     1 public class Test {
     2     @org.junit.jupiter.api.Test
     3     public void testDemo(){
     4         System.out.println("动态代理");
     5         UserDaoInterface target = new UserDao();
     6         UserDaoInterface proxy =(UserDaoInterface) new ProxyFactory(target).getInstance();
     7         proxy.save();
     8         System.out.println("原生对象:"+target.getClass());
     9         System.out.println("代理对象:"+proxy.getClass());
    10     }
    11 }

      运行结果:

    从结果中我们可以看出返回的是一个javaAPI的代理对象。

    四、CGLIB代理(无需接口)

      CGLIB代理不需要目标对象有实现接口,它通过构建目标对象的子类对目标功能进行扩展

      目标对象类:

    1 public class UserDao{
    2     public void save(){
    3         System.out.println("保存用户信息");
    4     }
    5 }

       代理对象类:

     1 public class CglibProxy implements MethodInterceptor {
     2 
     3     private Object target;
     4 
     5     public CglibProxy(Object target) {
     6         this.target = target;
     7     }
     8 
     9     //给目标对象创建代理对象
    10     public Object getProxyInstance(){
    11         /**
    12          * 1.工具类,允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类但是拦截了所有的方法。
    13          * 和Proxy不一样的是,不管是接口还是类他都能正常工作
    14          */
    15         Enhancer en = new Enhancer();
    16         /**
    17          * 2.设置父类
    18          */
    19         en.setSuperclass(target.getClass());
    20         /**
    21          * 3.设置回掉函数(因为MethodInterceptor继承了Callback类,默认执行intercept方法)
    22          */
    23         en.setCallback(this);
    24         /**
    25          * 4.创建子类
    26          */
    27         return en.create();
    28     }
    29 
    30     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    31         System.out.println("开始保存");
    32         Object returnObject = method.invoke(target,objects);
    33         System.out.println("保存结束");
    34         return returnObject;
    35     }
    36 }

        测 试类:

    1 public class Test {
    2     @org.junit.jupiter.api.Test
    3     public void testDemo(){
    4         System.out.println("cglib代理");
    5         UserDao userDao =(UserDao) new CglibProxy(new UserDao()).getProxyInstance();
    6         userDao.save();
    7     }
    8 }

      运行结果:

       

     

  • 相关阅读:
    [转]Maven 初学+http://mvnrepository.com/
    比较IDEA与Eclipse
    [web] 使用Promise封装fetch实现网络超时,终止请求的功能
    [web] 理解和使用Promise.all和Promise.race
    [Web] How to Test React and MobX with Jest
    [Web 测试] Jest单元测试的几个指标
    [Web] 取消Promise
    [安全分析] 安全分析中的威胁情报(一)
    [Web] 深入理解现代浏览器
    [Web] HTML5新特性history pushState/replaceState解决浏览器刷新缓存
  • 原文地址:https://www.cnblogs.com/caijh/p/7717929.html
Copyright © 2020-2023  润新知