• Spring5应用之Cglib动态代理


    作者简介:☕️大家好,我是Aomsir,一个爱折腾的开发者!
    个人主页Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客
    当前专栏Spring5应用专栏_Aomsir的博客-CSDN博客

    参考文献

    前言

    在上一篇文章中,我讲述了Spring动态代理底层具体实现之一的JDK动态代理,并在结尾抛出了本篇文章将要讲述的内容,本篇文章我将会着手于Spring动态代理底层具体实现的另一门技术之Cglib

    Cglib动态代理

    在上一章关于JDK动态代理的讨论中,我们确实注意到了其一个明显的限制:原始类和代理类都必须实现同一个接口,代理类方法添加额外功能并调用原始类方法。这种方式就像房屋中介:他们为租客提供服务,而租客可能并不知道背后的真正房东。但这种模式确实存在局限性,特别是当我们的系统设计中没有采用接口,或者原始类并没有实现任何接口而是直接写具体方法实现时

    那么,面对这种情况,我们怎么办?我们如何实现动态代理而不受到"必须实现接口"这一限制的约束?为了解决这个问题,Cglib(Code Generation Library) 应运而生。Cglib为我们提供了一种不基于接口的代理实现方式,它可以直接代理类。相对于JDK的代理方式,Cglib是基于继承父类(原始类)的,它会动态生成一个子类来覆盖原始类的方法,从而实现代理功能。这样既可以保证二者方法一致,这样既可以保证在代理类中提供新的实现,同时又调用了原始方法

    这种方法提供了更大的灵活性,特别是对于那些没有接口的类。在接下来的章节中,我们将深入探讨Cglib,了解它是如何提供这种强大功能的,以及它与JDK动态代理的区别和优缺点

    开发步骤

    使用Cglib创建动态代理的过程在逻辑上与JDK动态代理非常相似,但主要差异在于原始类不需要实现任何接口。以下是具体的步骤:

    1. 原始类的设计:首先,我们要设计并定义一个原始类。特别要注意的是,这里的原始类无需实现任何接口。这为那些基于纯类设计而非接口设计的应用提供了方便。
    2. 定义增强功能:就像在JDK动态代理中一样,您需要确定您希望添加到原始类中的额外或增强功能。
    3. 生成动态代理对象:使用Cglib的Enhancer对象可以为上一步中定义的原始类生成动态代理对象。为了实现此过程,确保项目中包含了Cglib的必要依赖。幸运的是这些依赖已经包含在spring-context库中,从而简化了集成过程
      在这里插入图片描述
    public class UserService {
    
        private static final Logger log = LoggerFactory.getLogger(UserService.class);
    
        public void login(String name, String password) {
            log.info("name = {}, password = {}", name, password);
        }
    
        public void register(User user) {
            log.info("{}", user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    public class TestCglibProxy {
    
        private static final Logger log = LoggerFactory.getLogger(TestCglibProxy.class);
    
        @Test
        public void test1() {
            // 创建原始对象
            UserService userService = new UserService();
    
            // 创建Cglib提供的Enhancer对象,用于设置好创建代理对象
            Enhancer enhancer = new Enhancer();
    
            // 设置类加载器
            enhancer.setClassLoader(TestCglibProxy.class.getClassLoader());
    
            // 设置被代理类(原始父类)
            enhancer.setSuperclass(UserService.class);
    
            // 设置方法拦截器
            MethodInterceptor methodInterceptor = new MethodInterceptor() {
                // 等同于InvocationHandler中的invoke方法
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    log.debug("log before");
    
                    Object ret = method.invoke(userService, objects);
    
                    log.debug("log after");
                    return ret;
                }
            };
            enhancer.setCallback(methodInterceptor);
    
            // 创建代理对象
            UserService userServiceProxy = (UserService) enhancer.create();
            userServiceProxy.login("Aomsir", "123456");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    总结

    经过前两篇文章的深入探讨,我们对Spring动态代理的底层实现有了更为全面的了解。其中,JDK动态代理和Cglib动态代理是两种最为核心的技术手段。

    JDK动态代理以接口为核心,通过Proxy.newInstance()方法为我们提供了创建代理对象的能力,要求原始类必须实现某个接口。而Cglib动态代理则更为灵活,不受接口的限制。通过Enhancer.create(),它直接生成原始类的子类,并在其中嵌入额外功能,从而实现代理。当然我们也可以通过设置让Spring在创建的时候只使用Cglib而不使用JDK

    Spring AOP聪明地整合了这两种机制,为开发者提供了无缝的体验。它默认采用JDK动态代理,但当遇到没有实现接口的原始类时,会智能切换到Cglib动态代理

    现在,再回过头来重新审视 BeanPostProcessor,我们可以发现更多之前可能忽略的细节和深层次的关联。正是这些细节和关联,使得Spring AOP的实现如此高效且灵活,满足了开发者的各种需求

    <aop:config proxy-target-class="true">
    aop:config>
    
    • 1
    • 2
  • 相关阅读:
    重温FPGA开发36
    Leetcode 49.字母异位词分组
    PHP表单token验证防CSRF攻击
    [附源码]java毕业设计企业人力资源管理系统
    分享一款嵌入式开源按键框架代码工程MultiButton
    zabbix6.4告警配置(短信告警和邮件告警),脚本触发
    详解BLEU的原理和计算
    13-盒子模型
    Java数组与八大排序
    Greenplum常用sql语句
  • 原文地址:https://blog.csdn.net/qq_43266723/article/details/133582661