JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
在 CGLIB 动态代理机制中 MethodInterceptor
接口和 Enhancer
类是核心。
你需要自定义 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法。
public interface MethodInterceptor extends Callback{ // 拦截被代理类中的方法 public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable; } Copy to clipboardErrorCopied
-
obj :被代理的对象(需要增强的对象)
-
method :被拦截的方法(需要增强的方法)
-
args :方法入参
-
methodProxy :用于调用原始方法
你可以通过 Enhancer
类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor
中的 intercept
方法。
CGLIB 动态代理类使用步骤
-
定义一个类;
-
自定义
MethodInterceptor
并重写intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的invoke
方法类似; -
通过
Enhancer
类的create()
创建代理类;
依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
代码示例
1、定义类
/**
* @author lin
* @version 1.0
* @date 2021/3/27 17:59
* @Description 1、定义一个类
*/
public class AliSmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
2、自定义MethodInterceptor
/**
* @author lin
* @version 1.0
* @date 2021/3/27 18:01
* @Description 2、实现 MethodInterceptor
*/
public class DebugMethodInterceptor implements MethodInterceptor {
/**
* @param obj 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param args 方法入参
* @param proxy 用于调用原始方法
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getDeclaringClass().equals(Object.class)) {
return method.invoke(this, args);
}
//调用方法之前,我们可以添加自己的操作
System.out.println("before method " + method.getName());
Object object = null;
if (method.getDeclaringClass().isInterface()) {
if (method.getName().equals("hello")) {
object = "hello";
}
} else {
object = proxy.invokeSuper(obj, args);
}
//调用方法之后,我们同样可以添加自己的操作
System.out.println("after method " + method.getName());
return object;
}
}
3、通过 Enhancer 创建代理类
/**
* @author lin
* @version 1.0
* @date 2021/3/27 18:06
* @Description 3、通过 Enhancer 类的 create()创建代理类;
*/
public class CglibProxyFactory {
public static <T> T getObject(Class<T> clazz) {
//1、创建 Enhancer 动态代理增加类
Enhancer enhancer = new Enhancer();
//2、设置 类加载器
enhancer.setClassLoader(clazz.getClassLoader());
//3、设置 被代理对象
enhancer.setSuperclass(clazz);
//4、设置 代理对象 ==> 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
//5、创建 增加对象
return (T) enhancer.create();
}
}
测试
@Test
public void test01() {
// 实际使用
AliSmsService aliSmsService = CglibProxyFactory.getObject(AliSmsService.class);
aliSmsService.send(" 恭喜你中奖了,本次放松的获奖验证码为: 88888 ");
}
//测试 代理接口
@Test
public void test02() {
// 实际使用
UserMapper userMapper = CglibProxyFactory.getObject(UserMapper.class);
System.out.println(userMapper.hello());
}
//接口
/**
* TODO
*
* @author 发哥讲Java
* @version 1.0
* @date 2021-03-10 16:27
*/
public interface UserMapper {
public String hello();
public String hello2();
}