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库中,从而简化了集成过程
java 复制代码
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);
    }
}
java 复制代码
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");
    }
}

总结

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

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

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

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

xml 复制代码
<aop:config proxy-target-class="true">
</aop:config>

参考文献

相关推荐
段ヤシ.9 分钟前
【Java框架】知识点汇总Day7:Spring Boot +Vue(持续更新)
vue.js·spring boot·后端·框架
codeejun9 分钟前
每日一 Go-72、分布式事务 & 一致性:本地消息表、事务消息、SAGA、TCC怎么选?
开发语言·分布式·golang
土狗TuGou9 分钟前
SQL进阶笔记 · 第1篇:存储引擎
java·数据库·笔记·后端·sql·mysql
科技互联.10 分钟前
2026轻量化图形引擎白皮书:PG官网发布渠道与分布式PG数据库架构解析
数据库·分布式·数据库架构
段一凡-华北理工大学14 分钟前
工业领域的Hadoop架构学习~系列文章10:数据序列化与压缩
大数据·人工智能·hadoop·分布式·学习·工业智能体·高炉炼铁智能化
雨落在了我的手上15 分钟前
Java数据结构(一):初识集合框架
java·开发语言
码语智行17 分钟前
Spring Security自定义AuthenticationManager实现手机号/密码双认证
java·后端·spring
SuniaWang17 分钟前
《AgentX 专栏》07-全链路可观测:用OpenTelemetry+Jaeger让每次AI对话都可追踪可复盘
java·人工智能·spring·架构·langchain·opentelemetry·agenx
fengxin_rou18 分钟前
【从零开始的JUC并发第五章】:线程池详解
java·jvm·spring
咖啡八杯22 分钟前
GoF设计模式——装饰模式
java·算法·设计模式·装饰器模式