• (十四)Spring之回顾代理模式



    Spring学习目录

    上一篇:(十三)Spring之JdbcTemplate

    下一篇:(十五)Spring之面向切面编程AOP

    回顾代理模式

    参考:代理模式Proxy Pattern
    不用JDK的动态代理,手写JDK动态代理

    动态代理常用技术

    在程序运行阶段,在内存中动态生成代理类,被称为动态代理,目的是为了减少代理类的数量。解决代码复用的问题。
    在内存当中动态生成类的技术常见的包括:

    • JDK动态代理技术:只能代理接口。参考代理模式Proxy Pattern
    • CGLIB动态代理技术:CGLIB(Code Generation Library)是一个开源项目。是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它既可以代理接口,又可以代理类,底层是通过继承的方式实现的。性能比JDK动态代理要好。(底层有一个小而快的字节码处理框架ASM。)
    • Javassist动态代理技术:Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。
      参考动态生成类–javassist的使用

    CGLIB动态代理技术

    CGLIB既可以代理接口,又可以代理类。底层采用继承的方式实现。所以被代理的目标类不能使用final修饰。
    使用CGLIB,需要引入它的依赖:

    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.3.0</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用CGLIB代理类
    创建一个目标类:

    /**
     *  目标类,不是接口了
     */
    public class TargetClass{
    
        public void sayHi(){
            System.out.println("Hi,动态 CGLEIB proxy");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    创建一个调用处理器类:
    在CGLIB当中不是InvocationHandler接口,是方法拦截器接口:MethodInterceptor
    实现的不是invoke方法了,是intercept方法
    intercept有一个目标对象的值,所以这个类不需要依赖目标对象了
    intercept方法有四个参数:

    • target:目标对象

    • method:目标方法

    • objects:目标方法参数

    • methodProxy:代理方法

    public class ProxyClass implements MethodInterceptor {
    
    
    
        /**
         *
         * @param target 目标对象
         * @param method 目标方法
         * @param objects 目标方法参数
         * @param methodProxy 代理方法
         * @return 代理类
         * @throws Throwable
         */
        @Override
        public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //方法调用之前功能增强
            System.out.println("目标方法执行前。。。。");
            Object result = methodProxy.invokeSuper(target,objects);//该方法真正调用目标方法
            //方法调用之后功能增强
            System.out.println("目标方法执行后。。。。");
            return result;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    编写测试程序:
    使用CGLIB在内存中为目标类生成代理类,并创建对象,有以下几个步骤:

    • 1.创建字节码增强器对象Enhancer
      这个对象是CGLIB库当中的核心对象,需要依靠它来生成代理类

    • 2.调用setSuperclass方法设置目标类/接口

    • 3.调用setCallback方法设置回调(等同于JDK动态代理当中的调用处理器InvocationHandler)

    • 4.调用create方法创建代理对象
      这一步会做两件事:

      • 其一:在内存中生成目标/接口的子类,其实就是代理类的字节码。
      • 其二:创建代理对象
    public class Client {
        public static void main(String[] args) {
            //1.创建字节码增强器对象
            Enhancer enhancer = new Enhancer();
            //2.设置目标类/接口
            enhancer.setSuperclass(TargetClass.class);
            //3.设置回调(等同于JDK动态代理当中的调用处理器InvocationHandler)
            enhancer.setCallback(new ProxyClass());
            //4.创建代理对象
            TargetClass targetClass = (TargetClass)enhancer.create();
            targetClass.sayHi();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    运行程序:出现错误
    请添加图片描述
    原因是jdk8版本之后有了java.base这个包,jdk8版本之前没有,导致找不到。
    需要加这两个参数
    –add-opens java.base/java.lang=ALL-UNNAMED
    –add-opens java.base/sun.net.util=ALL-UNNAMED
    第一步:点击右上方进行编辑配置
    在这里插入图片描述
    第二步:点击修改选项,勾选添加VM选项
    在这里插入图片描述
    第三步:添加两个参数,保存
    请添加图片描述
    再次运行:运行成功
    请添加图片描述

  • 相关阅读:
    别找了,Java生成MD5值直接用轮子就好了
    xxl-job环境搭建详细
    naive-ui-admin BasicTable 列表操作栏显示图标icon
    带刹车死区的互补输出与捕获实验
    X.509 V3证书的签发与验证
    PeLK:101 x 101 的超大卷积网络,同参数量下反超 ViT | CVPR 2024
    uniapp heckbox-group实现多选
    踩坑 Windows 服务来宿主 .NET 程序
    Maven安装详解
    【卫朋】项目管理:产品开发敏捷性的关键「项目经理及路线图」
  • 原文地址:https://blog.csdn.net/weixin_45832694/article/details/128020976