不仅可以接管接口类的方法还可以接管普通类的方法
一些开源框架都采用了cglib:Hibernate Spring Guice
CGLib 的底层是 Java 字节码操作框架——ASM (https://asm.ow2.io)
在JDK8之前CGLib动态代理比JDK的动态代理(使用Java反射)效率要高
唯一要注意的是,如果被代理的类被final修饰,那么它不可被继承,即不可被代理,同样如果被代理的类中存在final修饰的方法,那么该方法也不可被代理,因为CGLib原理是动态生成被代理类的子类
final类不能被继承,final方法不能被复写
导入maven依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
目标接口
public interface TargetInterface {
String sayHello(String name);
String sayThanks(String name);
}
目标接口实现类
public class TargetInterfaceImpl implements TargetInterface{
@Override
public String sayHello(String name) {
//限流
return "Hello, " + name;
}
@Override
public String sayThanks(String name) {
//限流
return "Thanks, " + name;
}
}
cglib代理类
/**
* author:qxstart
* TargetProxy 类还不是一个真正的代理类,它是代理类的一部分
*/
public class TargetProxy implements MethodInterceptor {
/**
* 获取真正的代理类
*
* @param clazz
* @param <T>
* @return
*/
public <T> T getProxy(Class<T> clazz) {
// 字节码增强的一个类
Enhancer enhancer = new Enhancer();
// 设置父类
// enhancer.setSuperclass(clazz);
enhancer.setInterfaces(new Class[]{clazz});
// 设置回调类
enhancer.setCallback(this);
// 创建代理类
return (T) enhancer.create();
}
/**
* 既可以sayHello,也可以拦截 sayThanks
*
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 方法之前执行逻辑
System.out.println(method.getName() + "数据缓存start。。。。。。。");
// 调用目标方法
Object result = proxy.invokeSuper(obj, args);
System.out.println(result);
//如果设置父类为接口,就需要像mybatis一样自己实现接口
// System.out.println("sayHello..........");
// 方法之后执行逻辑
System.out.println(method.getName() + "数据缓存end。。。。。。。");
return result;
}
}
测试类
public class Test {
public static void main(String[] args) {
// 通过参数设置,把动态代理生成的class文件输出到磁盘上,默认是不会输出到磁盘的,所以动态代理生成的类我们是看不见摸不着的
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:/code");
TargetProxy targetProxy = new TargetProxy();
// 拿到目标类的代理类
//如果目标代理类TargetProxy中通过 enhancer.setSuperclass(clazz) 设置父类, 那么这里的targetProxy.getProxy(TargetInterfaceImpl.class); 传入目标接口的实现类
TargetInterface targetInterface = targetProxy.getProxy(TargetInterfaceImpl.class);
//如果目标代理类TargetProxy中通过 enhancer.setInterfaces(new Class[]{clazz}) 设置父类, 那么这里 targetProxy.getProxy(TargetInterface.class); 传入用目标接口 并且TargetProxy的invoke方法中的 调用目标方法这一句 (Object result = proxy.invokeSuper(obj, args)) 需要重写目标接口的方法
// TargetInterface targetInterface = targetProxy.getProxy(TargetInterface.class);
targetInterface.sayHello("张无忌");
targetInterface.sayThanks("张无忌");
}
}
输出结果