0 前言
重温一下,何为代理:
举个栗子,你准备自己到楼下去买咖啡,但是这时候突然有事走不开,你就让你的同事帮你买咖啡(顺便请他喝一杯hhh),因此你的同事就是代理类,你就是被代理类,而买咖啡这个行为就是你们需要执行的。
-
书接上文,JDK 动态代理机制只能代理实现了 invocationHandler 接口的类,而 CGLIB 动态代理是针对子类来实现代理的,其主要原理是针对目标类生成一个子类,覆盖目标类的方法实现增强。这篇文章主要介绍下 CGLIB 动态代理
-
说明:CGLIB 动态代理需要引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1 具体实现
-
定义一个功能接口(买咖啡)
/**
* @Author Jasper
* @Time 2024/01/22
*/
public interface BuyCoffeeService {
void buyCoffee();
}
-
被代理对象(实现类)
/**
* @Author Jasper
* @Time 2024/01/22
*/
public class BuyCoffeeServiceImpl implements BuyCoffeeService {
@Override
public void buyCoffee() {
System.out.println("到楼下买咖啡!");
}
}
-
创建一个 CGLIB 动态代理处理器,实现 MethodInterceptor 接口
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author Jasper
* @Time 2024/01/22
*/
public class CglibProxyFactory implements MethodInterceptor{
/** 维护一个目标对象 */
private Object target;
/**
* 过构造器传入目标对象
* @param target
*/
public CglibProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
// 创建enhancer,用于生成一个子类,去生成代理对象
Enhancer enhancer = new Enhancer();
// 目标对象类作为代理类的父类
// CGLIB体现的是继承思想,所以我们需要把代理类作为我们目标类的一个子类,也就是把目标类设置为父类,代理类去继承它
enhancer.setSuperclass(target.getClass());
// 设置 enhancer 的回调对象
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
/**
* @param o 代理对象
* @param method 被代理对象的方法
* @param objects 方法入参
* @param methodProxy 代理方法
* @return Object
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB 代理开始...");
Object obj = method.invoke(target, objects);
System.out.println("CGLIB 代理结束...");
return obj;
}
}
-
测试类:
import top.ezjava.demo.dynamicProxy.jdkProxy.BuyCoffeeServiceImpl;
/**
* @Author Jasper
* @Time 2023/2/7
*/
public class TestCglibProxy {
public static void main(String[] args) {
// 创建目标对象
BuyCoffeeServiceImpl buyCoffeeService = new BuyCoffeeServiceImpl();
// 传入目标对象,得到代理类
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(buyCoffeeService);
// 得到代理对象,进行强转
BuyCoffeeServiceImpl proxyInstance = (BuyCoffeeServiceImpl) cglibProxyFactory.getProxyInstance();
// 通过代理对象调用目标对象的方法
proxyInstance.buyCoffee();
}
}
/**
输出结果:
CGLIB 代理开始...
到楼下买咖啡!
CGLIB 代理结束...
*/
3 总结
-
JDK 动态代理和 CGLIB 动态代理的区别:
1、JDK 动态代理实现接口的思想,CGLIB 动态继承的思想
2、JDK 动态代理实现 InvocationHandler 接口,CGLIB 动态代理实现 MethodInterceptor 接口
3、如果对象有接口实现就选择 JDK 动态代理,如果没有接口实现就选择 CGILB 动态代理
4 补充
-
SpringBoot 2.x 开始,默认实现 CGLIB 动态代理,其原因是 CGLIB 动态代理不容易出转换错误,原话如下:This was changed in 1.4 (see 5423). We’ve generally found cglib proxies less likely to cause unexpected cast exceptions.
-
如果一定要使用 JDK 动态代理,需要在 application.yaml 文件里进行如下配置:
spring:
aop:
proxy-target-class: false # true为cglib代理(默认),false为jdk代理
-
CGLIB 动态代理就到此为止啦,如有错误,欢迎指正。
-
创作不易,感谢阅读,若遇到问题,可以关注此微信公众号留言反馈,希望能够帮助到您。
原文始发于微信公众号(EzCoding):聊一聊 CGLIB 动态代理
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/203649.html