1. 介绍CGLib
在Java领域,CGLib(Code Generation Library)是一个强大的字节码操作库,常用于实现动态代理和类的增强。与Java标准库的动态代理不同,CGLib在代理时不需要目标类实现接口,这使得它在某些场景下更加灵活。
2. CGLib动态代理的基本原理
CGLib的动态代理机制是通过生成目标类的子类来实现的。当你需要代理一个类时,CGLib会创建一个该类的子类,并在子类中重写需要代理的方法。这允许你在方法调用前后插入自定义逻辑,实现方法的增强。
3. CGLib的使用步骤
- 1.引入CGLib库的依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
- 创建一个Enhancer对象,用于生成代理类
- 设置目标类和拦截器(MethodInterceptor
- 设置拦截器
- 测试
4. 实例:使用CGLib实现方法增强
通过一个实际的示例,演示如何使用CGLib实现方法的增强。展示如何创建拦截器(MethodInterceptor),并在方法调用前后插入自定义的逻辑,从而实现对方法的增强。
创建一个Enhancer对象,用于生成代理类
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(DemoServiceImpl.class); enhancer.setCallback( new TargetInterceptor());
- 设置目标类和拦截器(MethodInterceptor)
publicclassDemoServiceImp{ publicvoidride(){ System.out.println("骑车啦"); } }
publicTargetInterceptorimplementsMethodIntercetor{ publicObjectintercept(Objecto, Methodmethod, Object[] objects, MethodProxymethodProxy) throwsThrowable { System.out.println("===intercept before ==="); Objectresult=methodProxy.invokeSuper(o,objects); System.out.println("===intercept after===="); returnresult; } }
使用Enhancer创建代理对象
@Test public void testEnhancer(){ //设置class的字节码的生成目录 方便查看 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/xxxx/Documents/workspaces/Staging/"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(DemoServiceImpl.class); enhancer.setCallback( new TargetInterceptor()); DemoServiceImpl demoServiceImpl = (DemoServiceImpl)enhancer.create(); //拿到的其实是已经增强的类 demoServiceImpl.ride(); }
再去查看下class 生成的信息:
第一个是代理类,可以大概的看下情况
5. 与Java标准动态代理的对比
cglib 其实跟jdk proxy 都是为了在运行中解决代理的问题。
cglib 是来自于第三方包,基于ASM来实现的,内部比较复杂 jdk 是自带的,会随着jdk版本升级与更新
最大的区别是cglib 可以直接操作没有实现接口的类,相当于jdk proxy来说,
1.无接口限制
2.继承代理: 字节码中可以看出是直接extends xxx 生成的代理类
3.调优性能优化:在CGLIB中,方法调用被转发到目标方法的方式更加直接,不需要通过InvocationHandler
的invoke
方法来间接调用。这样可以避免一层反射调用
4.缓存机制: CGLIB在生成代理类时会缓存已经生成过的类,避免重复生成。这在创建多个相同代理类实例时可以提高性能。JDK动态代理在每次生成新的代理实例时都会重新生成相应的字节码。
使用场景:目标实现了接口,希望代理接口的方法,使用jdk proxy. AOP(日志,事务)
想要不需要实现接口的代理 在一定程度提升性能,那么就用cglib
6. CGLib的局限性
cglib局限性在于它是通过继承的方式来实现代理的,但是在日常开发中,会存在final修饰的情况,方法不能修改,变量不能修改 类不能被继承,也就意味着无法通过cglib进行增强,故不支持final 修饰的场景。遇到这种情况的时候,可以适当的转换思维,用jdk proxy
7. 总结
结尾: CGLib作为一个强大的字节码操作库,为Java动态代理提供了一种灵活且功能丰富的方式。通过深入了解CGLib的工作原理和使用方法,你可以更好地利用它来实现代码增强和动态代理,为你的应用程序增加更多的灵活性和扩展性。