• 代理模式:静态代理、JDK动态代理、Cglib动态代理


    一、代理模式

    1. 概念:为一个对象提供一种代理,用代理控制对象的访问,而不是直接访问对象

    2. 使用场景:

    a. 远程代理:位于两个不同的地址空间对象的访问

    b. 虚拟代理:消耗资源较少的对象代表消耗资源多的对象

    c. 缓冲代理:缓存

    d. 保护代理:控制对一个对象的不同级别的访问权限

    e. 智能引用:为一个对象的访问(引用)提供一些额外的操作,比如校验、记日志

    二、静态代理

    1. 编译时确定了代理与被代理者的关系,又叫编译时增强

    2. 静态代理由接口、业务实现类、业务代理类组成

    a. 业务实现类实现业务接口,负责具体的业务

    b. 业务代理类也要实现业务接口,负责拦截、过滤、预处理

    3. 使用时,不是通过调用业务实现类的方法,而是通过调用业务代理类的同名方法,先创建业务实现类的对象,传入业务代理类的构造方法里

    4. 缺点:一个业务代理类只能对一个业务实现类进行包装,不能对多个;多个业务代码会有重复

    三、动态代理:

    1. 运行时才真正确定代理关系,又叫运行时增强

    2. 有一个代理类,能代理所有业务实现类的方法调用

    3. 根据传进来的业务实现类和方法名进行具体调用

    4. 与静态代理比较:可以对多个对象进行代理,比静态代理更灵活,不用写多余代码;而静态代理对多个对象进行代理需要写多个代理类

    四、JDK动态代理,针对接口,核心是InvocationHandler

    1. 在程序调用到代理类对象时,才由JVM真正创建

    2. JVM根据业务实现类对象和方法名,动态创建一个代理类.class文件被字节码执行,在调用方法时通过这个代理类对象里的方法调用

    3. 业务类实现业务接口,如果没有业务接口,不能使用JDK动态代理

    4. 代理类通过实现InvocationHandler接口创建动态代理类,而不需要实现业务接口,所有代理类都一个写法是通用的

    public class BookFacadeProxy implements InvocationHandler {  // InvocationHandler接口,被动态代理类实现,负责处理被代理对象的操作
        private Object target;//这其实业务实现类对象,用来调用具体的业务方法 
        /** 
         * 绑定业务对象并返回一个代理类  
         */  
        public Object bind(Object target) {  
            this.target = target;  //接收业务实现类对象参数
    
           // 通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
           // 创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                    target.getClass().getInterfaces(), this); }  
        /** 
         * 包装调用方法:进行预处理、调用后处理 
         */  
        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;  
        }  
      
    }

    5. 经过上面两步,已经创建了业务实现类对象和代理类对象,将其绑定,绑定的时候就是通过反射,然后代理使用

    public static void main(String[] args) {  
            BookFacadeImpl bookFacadeImpl=new BookFacadeImpl();
            BookFacadeProxy proxy = new BookFacadeProxy();  // 创建动态代理类实例
            BookFacade bookfacade = (BookFacade) proxy.bind(bookFacadeImpl);  // 绑定才能动态代理
            bookfacade.addBook();  
        }

    5. JDK动态代理的缺点:只能代理实现了接口的业务类方法,如果业务类自己定义的方法,则不能代理

    五、Cglib(Code Generation Library)动态代理,针对类和接口,核心是MethodInterceptor

    1. Cglib是代码生成类库,可以在运行期间动态扩展类和接口,底层使用Java字节码操作框架ASM实现

    2. 原理:对要代理的业务类,生成一个子类,并覆盖业务类里的所有非final方法,在子类中采用方法拦截的技术,拦截所有父类方法的调用,顺势织入横切逻辑

    3. 缺点:对于final方法,无法进行代理

    4. 使用:

    a. 定义业务类,不需要实现任何接口

    b. 定义拦截器,在调用目标方法时,Cglib会回调MethodInterceptor接口里的intercept方法进行拦截

    public class BookFacadeCglib implements MethodInterceptor {  
        private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
      
        //相当于JDK动态代理中的绑定
        public Object getInstance(Object target) {  
            this.target = target;  //给业务对象赋值
            Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类,核心实现
            enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
            //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
            enhancer.setCallback(this); 
           // 创建动态代理类对象并返回  
           return enhancer.create(); 
        }
        // 实现回调方法 
        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; 
        }

    六、总结

    1. 静态代理比动态代理更符合OOP原则,在日常开发中使用也比较多 

    2. 动态代理在开发框架的时候用的比较多

    3. Cglib动态代理运行方法时的性能,比使用反射的JDK动态代理要快,但是在创建对象的时候比较慢,所以适用场景不一样,无需频繁创建代理对象时(比如单例的代理对象),使用cglib,其他场景使用JDK

    4. Spring AOP默认使用JDK,当没有接口时,会强制使用cglib

    参考:

    https://blog.csdn.net/ShuSheng0007/article/details/80864854

  • 相关阅读:
    正则表达式 1
    14 同步 1
    14 线程属性
    14 线程状态
    14 线程
    window.location.hostname与 window.location.host 区别
    泛型 的通配符类型 extends super
    svn拷贝一个项目作为新项目
    List Collections sort
    && 和 || 逻辑运算符
  • 原文地址:https://www.cnblogs.com/june0816/p/6478100.html
Copyright © 2020-2023  润新知