CGLIB动态代理应用和原理

CGLIB动态代理是一种在运行时增强字节码的技术,它通过将代理对象设置为被目标对象的子类来增强目标方法。

1.CGLIB动态代理在Spring AOP中的应用

下面我们实现一个Spring AOP的小例子

首先定义一个目标类,其中包含了我们要增强的方法

@Component
public class Chinese implements Person {
    public String sayHello(String name) {
        System.out.println("正在执行sayHello方法");
        return name + " Hello, Spring Aop";
    }

    public void eat(String food) {
        System.out.println("我正在吃: " + food);
    }
}
接着定义一个后置增强处理切面

@Aspect
public class AfterReturningAdviceTest {
    @AfterReturning(returning = "rvt", pointcut = "execution(* com.cmb.china.springaop.*.*(..))")
    public void log(Object rvt) {
        System.out.println("获取目标方法返回值: " + rvt);
        System.out.println("模拟记录日志功能");
    }
}
在定义一个环绕增强处理切面

@Aspect
public class AroundAdviceTest {
    @Around("execution(* com.cmb.china.springaop.*.*(..))")
    public Object processTx(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行目标方法之前,模拟开始事务...");
        Object rvt = joinPoint.proceed(new String[]{"被改变的参数"});
        System.out.println("执行目标方法之后,模拟结束事务");
        return rvt + " 新增的内容";
    }
}
最后在Spring配置文件中开启AspectJ支持

<context:component-scan base-package="com.cmb.china">
    <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<aop:aspectj-autoproxy/>
进行测试

public class BeanTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person chinese = context.getBean("chinese", Person.class);
        System.out.println(chinese.sayHello("张三"));
        chinese.eat("西瓜");
        System.out.println(chinese.getClass());
    }
}
运行结果

  执行目标方法之前,模拟开始事务...
正在执行sayHello方法
执行目标方法之后,模拟结束事务
获取目标方法返回值: 被改变的参数 Hello, Spring Aop 新增的内容
模拟记录日志功能
被改变的参数 Hello, Spring Aop 新增的内容
执行目标方法之前,模拟开始事务...
我正在吃: 被改变的参数
执行目标方法之后,模拟结束事务
获取目标方法返回值: null 新增的内容
模拟记录日志功能
class com.cmb.china.springaop.Chinese$$EnhancerBySpringCGLIB$$464c626a

从结果中可以看出,切面已经织入了目标方法,在执行目标方法的前后执行了我们在切面中定义的增强方法。@AfterReturning注解是在目标方法执行之后织入增强方法,@Around注解是在目标方法执行前后织入增强方法。从chinese.getClass()的结果com.cmb.china.springaop.Chinese&$$EnhancerBySpringCGLIB$$464c626a可知,动态代理类是由CGLIB通过Enhancer生成的。

2.CGLIB动态代理类的生成过程
下面我们再来写一个例子直观感受一下CGLIB生成代理类的过程
先为CGLIB提供一个拦截器实现类
public class AroundAdvice implements MethodInterceptor {
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行目标方法之前,模拟事务开始");
        Object rvt = methodProxy.invokeSuper(target, new String[]{"被改变的参数"});
        System.out.println("执行目标方法之后,模拟结束事务...");
        return rvt + " 新增的内容";
    }
}
AroundAdvice实现了MethodInterceptor接口,实现了intercept方法,其中的target是目标对象,method是目标方法,args是目标方法的实际入参,methodPorxy是目标方法的代理方法。
下面实现一个为Chinese对象生成代理类的工厂
public class ChineseProxyFactory {
    public static Chinese getAuthInstance() {
        Enhancer enhancer = new Enhancer();
        // 通过运行时修改字节码设置代理类的父类
        enhancer.setSuperclass(Chinese.class);
        enhancer.setCallback(new AroundAdvice());
        return (Chinese) enhancer.create();
    }
}
测试
public class Test {
    public static void main(String[] args) {
        Chinese chinese = ChineseProxyFactory.getAuthInstance();
        System.out.println(chinese.sayHello("孙悟空"));
        chinese.eat("西瓜");
        System.out.println(chinese.getClass());
    }
}
运行结果
执行目标方法之前,模拟事务开始
正在执行sayHello方法
执行目标方法之前,模拟事务开始
执行目标方法之前,模拟事务开始
执行目标方法之后,模拟结束事务...
执行目标方法之后,模拟结束事务...
被改变的参数 Hello, Spring Aop 新增的内容
执行目标方法之前,模拟事务开始
我正在吃: 被改变的参数
执行目标方法之前,模拟事务开始
执行目标方法之前,模拟事务开始
执行目标方法之后,模拟结束事务...
执行目标方法之后,模拟结束事务...
class com.cmb.china.springaop.Chinese$$EnhancerByCGLIB$$83b98ab0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值