likes
comments
collection
share

Spring5应用之Cglib动态代理

作者站长头像
站长
· 阅读数 9

前言

在上一篇文章中,我讲述了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库中,从而简化了集成过程 Spring5应用之Cglib动态代理
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);
    }
}
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的实现如此高效且灵活,满足了开发者的各种需求

<aop:config proxy-target-class="true">
</aop:config>

参考文献