本文已参与「新人创作礼」活动,一起开启掘金创作之路。
动态代理常用的实现方式是发射. 但动态代理不止有反射这一种实现方式.
eg: 动态代理也可以是通过CGLib来实现,而CGLib是基于ASM(一个java字节码操作框架),而实现的.
简单说: 动态代理是一种行为方式,而反射或ASM只是它的一种实现手段而已
JDKPorxy 和CGLib区别:
- JDK Proxy 是java语言自带的功能,无需加载三方 jar来实现.
- java对 JDK Proxy 提供了稳定的支持,并且会持续提升和更新JDK Proxy, eg: java 8 中JDK Proxy 性能相比于之前版本提升了很多
- JDK Proxy 是通过拦截器加 反射的方式实现的
- JDK Proxy只能代理集成接口的类
- JDK Proxy 实现和调用起来比较简单
- CGLib 是第三方提供的工具,基于ASM实现的,性能比较高
- CGLib 无需通过接口来实现,它是通过实现子类的方式来完成调用的
public class JDKProxyExample {
static interface Car {
void run();
}
static class Bus implements Car{
@Override
public void run() {
System.out.println("Bus running");
}
}
static class Taxi implements Car{
@Override
public void run() {
System.out.println("Taxi running");
}
}
// 实现 InvocationHandler 接口
static class JDKProxy implements InvocationHandler {
// 代理对象
private Object target;
// 获取代理对象实例
public Object getInstance(Object target) {
this.target = target;
// 获得代理的对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),JDKProxy.this);
}
/**
* 执行代理方法
* @param proxy 代理对象
* @param method 代理方法
* @param args 方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理之前的业务处理");
Object invoke = method.invoke(target, args);
return invoke;
}
}
public static void main(String[] args) {
JDKProxy jdkProxy = new JDKProxy();
Car instance = (Car) jdkProxy.getInstance(new Taxi());
instance.run();
Car instance2 = (Car)jdkProxy.getInstance(new Bus());
instance2.run();
}
}
依赖:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author xulihui
* @date 2020/4/7 13:10
*/
public class CGLibExample {
static class Car {
public void run() {
System.out.println("Car running");
}
}
static class CGLibProxy implements MethodInterceptor {
// 接收代理对象
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
// 设置父类为示例
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建并返回代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法调用前业务处理");
// 执行调用方法
Object invoke = methodProxy.invoke(o, objects);
return invoke;
}
}
public static void main(String[] args) {
// 创建CGLib代理类
CGLibProxy cgLibProxy = new CGLibProxy();
// 初始化代理对象
Car instance = (Car)cgLibProxy.getInstance(new Car());
// 执行方法
instance.run();
}
}
spring框架中同时使用了两种动态代理 JDK Proxy 和CGLib,
当bean实现了接口时,Spring 就会使用CGLib
没有实现接口的时候,就会使用CGLib, 也可以在配置中强制使用CGLib, 只需要在Spring 配置中添加 <aop:aspectj-autoproxy proxy-target-class="true"/> 即可。