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 办法。
3.2.2. CGLIB 动静代理类应用步骤
定义一个类;
自定义 MethodInterceptor 并重写 intercept 办法,intercept 用于拦挡加强被代理类的办法,和 JDK 动静代理中的 invoke 办法相似;
通过 Enhancer 类的 create()创立代理类;
3.2.3. 代码示例
不同于 JDK 动静代理不须要额定的依赖。CGLIB(Code Generation Library) 理论是属于一个开源我的项目,如果你要应用它的话,须要手动增加相干依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1. 实现一个应用阿里云发送短信的类
package github.javaguide.dynamicProxy.cglibDynamicProxy;
public class AliSmsService {
public String send(String message) {System.out.println("send message:" + message);
return message;
}
}
2. 自定义 MethodInterceptor(办法拦截器)
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
- 自定义 MethodInterceptor
*/
public class DebugMethodInterceptor implements MethodInterceptor {
/**
* @param o 被代理的对象(须要加强的对象)* @param method 被拦挡的办法(须要加强的办法)* @param args 办法入参
* @param methodProxy 用于调用原始办法
*/
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 调用办法之前,咱们能够增加本人的操作
System.out.println("before method" + method.getName());
Object object = methodProxy.invokeSuper(o, args);
// 调用办法之后,咱们同样能够增加本人的操作
System.out.println("after method" + method.getName());
return object;
}
}
3. 获取代理类
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 DebugMethodInterceptor());
// 创立代理类
return enhancer.create();}
}
4. 理论应用
AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
aliSmsService.send(“java”);
运行上述代码之后,控制台打印出:
before method send
send message:java
after method send
JDK 动静代理和 CGLIB 动静代理比照
JDK 动静代理只能只能代理实现了接口的类或者间接代理接口,而 CGLIB 能够代理未实现任何接口的类。另外,CGLIB 动静代理是通过生成一个被代理类的子类来拦挡被代理类的办法调用,因而不能代理申明为 final 类型的类和办法。
就二者的效率来说,大部分状况都是 JDK 动静代理更优良,随着 JDK 版本的降级,这个劣势更加显著。