Cglib 动态代理
-
介绍
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;
}
- obj :被代理的对象(需要增强的对象)
- method :被拦截的方法(需要增强的方法)
- args :方法入参
- methodProxy :用于调用原始方法
可以通过 Enhancer
类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor
中的 intercept
方法。
-
使用步骤
- 定义一个类
- 自定义
MethodInterceptor
并重写intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中invoke
方法类似 - 通过
Enhancer
类的create()
创建代理类
-
代码示例
不同于 JDK 动态代理不需要额外的依赖。CGLIB(Code Generation Library) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1. 定义实现发送消息的类
package com.format.service;
public class SmsCglibService {
public String send(String message) {
System.out.println("send message : " + message);
return message;
}
}
2. 自定义 MethodInterceptor(方法拦截器)
package com.format.proxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DynamicMethodInterceptor implements MethodInterceptor {
/**
* @param o 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param objects 方法入参
* @param methodProxy 用于调用原始方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//真实方法调用前
System.out.println("before method : " + method.getName());
Object result = methodProxy.invokeSuper(o,objects);
//真实方法调用后
System.out.println("end method : " + method.getName());
return result;
}
}
3. 获取代理类
package com.format.proxy;
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz){
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
//设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
//设置被代理类
enhancer.setSuperclass(clazz);
//设置方法拦截器
enhancer.setCallback(new DynamicMethodInterceptor());
//创建代理类
return enhancer.create();
}
}
4. 使用
package com.format.main;
import com.format.proxy.CglibProxyFactory;
import com.format.service.SmsCglibService;
public class ProxyTestMain {
public static void main(String[] args) {
SmsCglibService cglibService = (SmsCglibService)CglibProxyFactory.getProxy(SmsCglibService.class);
cglibService.send("hello");
}
}
控制台打印出
before method : send
send message : hello
end method : send