• Spring AOP中的代理模式


    一、代理模式

    类A需要完成的工作由类B去完成,类B实际上是在类A的基础上作了一层封装,类B包括原始类A的业务逻辑以及前后的扩展逻辑,实现了类A的功能扩展
    类A→被代理类/代理目标类/委托类
    类B→代理类

    二、静态代理

    手动创建代理类,代理类的实现方法中对对原始的业务逻辑进行了扩展,两个要点:

    1. 代理类、委托类需要实现相同的接口
    2. 代理类中持有委托类的对象

    特点:

    1. 每进行一次功能扩展,就要对委托类手动创建至少一个相对应的代理类
    2. 原理简单,但是程序过于繁琐与臃肿

    定义一个接口,

    package com.imooc.spring.aop.service;
    
    public interface UserService {
        public void createUser();
    }
    

    委托类,

    package com.imooc.spring.aop.service;
    
    public class UserServiceImpl implements UserService{
        public void createUser() {
            System.out.println("执行创建用户业务逻辑");
        }
    }
    

    代理类,

    package com.imooc.spring.aop.service;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    //静态代理是指必须手动创建代理类的代理模式使用方式
    public class UserServiceProxy implements UserService{
        //持有委托类的对象
        private UserService userService ;
        public UserServiceProxy(UserService userService){
            this.userService = userService;
        }
    
        public void createUser() {
            //添加其他的逻辑,实现功能扩展
            System.out.println("========静态代理前置扩展功能======");
            userService.createUser();
            System.out.println("========静态代理后置扩展功能======");
        }
    }
    

    测试入口类,

    package com.imooc.spring.aop;
    
    import com.imooc.spring.aop.service.UserService;
    import com.imooc.spring.aop.service.UserServiceImpl;
    import com.imooc.spring.aop.service.UserServiceProxy;
    import com.imooc.spring.aop.service.UserServiceProxy1;
    
    public class Application {
        public static void main(String[] args) {
            UserService userService = new UserServiceProxy(new UserServiceImpl());
            userService.createUser();
        }
    }
    
    

    测试结果,

    ========静态代理前置扩展功能======
    执行创建用户业务逻辑
    ========静态代理后置扩展功能======
    

    三、动态代理

    动态代理分为JDK动态代理、CGLib动态代理

    JDK动态代理

    接口、委托类沿用上面的Userservice、UserserviceImpl,JDK动态代理需要实现InvocationHandler接口,重写invoke方法 ,

    package com.imooc.spring.aop.service;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * InvocationHandler是JDK提供的反射类,用于在JDK动态代理中对目标方法进行增强
     * InvocationHandler实现类与切面类的环绕通知类似
     */
    public class ProxyInvocationHandler implements InvocationHandler {
        private Object target;//目标对象,对所有类生效,所以目标对象类型选择Object
        public ProxyInvocationHandler(Object target){
            this.target = target;
        }
        /**
         * 在invoke()方法对目标方法进行增强
         * @param proxy 代理类对象
         * @param method 目标方法对象
         * @param args 目标方法实参
         * @return 目标方法运行后返回值
         * @throws Throwable 目标方法抛出的异常
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("========JDK动态代理前置扩展功能======");
            Object ret = method.invoke(target, args);//调用目标方法,类似环绕通知中的ProceedingJoinPoint.proceed()
            System.out.println("========JDK动态代理后置扩展功能======");
            return ret;
        }
    
    }
    

    测试入口类,

    package com.imooc.spring.aop;
    
    import com.imooc.spring.aop.service.*;
    
    import java.lang.reflect.Proxy;
    
    public class Application {
        public static void main(String[] args) {
            UserService userService = new UserServiceImpl();
            ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
            //动态创建代理类
            //Proxy.newProxyInstance 根据已经存在的接口,实现其相对应的代理类
            UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                    userService.getClass().getInterfaces(),
                    invocationHandler);
            userServiceProxy.createUser();
    
            
        }
    }
    

    测试结果,

    ========JDK动态代理前置扩展功能======
    执行创建用户业务逻辑
    ========JDK动态代理后置扩展功能======
    

    JDK动态代理逻辑框图

    JDK动态代理主要包括两个步骤:
    1.UserService userServiceProxy =Proxy.newProxyInstance();//创建代理类,newProxyInstance()根据已有的接口,生成对应的代理类
    2.userServiceProxy.createUser(); //代理类与委托类实现了相同的接口,代理类实现接口中的业务逻辑

    1.Proxy.newProxyInstance()在执行步骤:

    1. 在本地硬盘上创建$Proxy0.class代理类的class文件
    2. 确定代理类的包名:com.sun.proxy
    3. 确定代理类的类名:com.sun.proxy.$Proxy0
    4. ProxyGenerator.generateProxyClass生成代理类的代码,具体可参考图中的伪代码
    5. defineclass0将硬盘中的.Class字节码文件通过被代理类的classLoder(类加载器),载入到当前JVM的方法区中,并通过new $Proxy0实例化对象,$Proxy0对象中包含UserServiceImpl对象的引用
    6. 第5步得到代理类的对象userServiceProxy ,至此完成了Proxy.newProxyInstance()的所有工作

    动态生成的代理类$Proxy0与委托类UserServiceImpl实现了相同的接口UserService

    代理类$Proxy0中包含委托类的对象的引用:targetObject

    实现接口中的方法:具体实现代码来自InvocationHandler实现类中的invoke方法

    2.调用userServiceProxy.createUser();实现委托类的功能扩展,createUser()中的代码对应伪代码中方法中的业务逻辑

    CGLib动态代理

    委托类实现了接口,可以通过JDK动态代理实现功能扩展,委托类没有接口,则通过CGLib第三方组件实现功能扩展
    CGLib第三方组件继承需要增强的类,产生一个子类,并重写父类中的方法,实现功能扩展

    参考文献

    1.https://www.cnblogs.com/teach/p/10763845.html

    扩展阅读

    1.类加载机制 https://www.cnblogs.com/insist-bin/p/11223876.html

  • 相关阅读:
    Dialog 对话框的文字与输入框不对齐
    ag-grid动态生成表头及绑定表数据
    ag-grid实时监测复选框变化
    Java-分页工具类
    Java-日期转换工具类
    文件上传与下载
    IDEA的安装与激活
    熟悉IDEA工具的使用
    缓存三大问题的解决办法
    制作一个省份的三级联动菜单
  • 原文地址:https://www.cnblogs.com/little-mao2020/p/14235065.html
Copyright © 2020-2023  润新知