共计 3007 个字符,预计需要花费 8 分钟才能阅读完成。
JDK 动静代理
jdk 动静代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务办法前调用 InvocationHandler 解决。代理类必须实现 InvocationHandler 接口,并且,JDK 动静代理只能代理实现了接口的类,没有实现接口的类是不能实现 JDK 动静代理。
应用 JDK 动静代理类根本步骤:
1、须要被代理的类和接口
public interface OrderService {public void save(UUID orderId, String name);
}
public class OrderServiceImpl implements OrderService {
@Override
public void save(UUID orderId, String name) {System.out.println("call save()办法,save:" + name);
}
}
2、代理类,须要实现 InvocationHandler 接口,重写 invoke 办法
public class JDKProxy implements InvocationHandler {
// 须要代理的指标对象
private Object targetObject;
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
this.targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 被代理对象
OrderServiceImpl bean = (OrderServiceImpl) this.targetObject;
Object result = null;
// 切面逻辑(advise),此处是在指标类代码执行之前
System.out.println("---before invoke----");
if (bean.getUser() != null) {result = method.invoke(targetObject, args);
}
System.out.println("---after invoke----");
return result;
}
}
3、应用 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务办法。
public class AOPTest {public static void main(String[] args) {JDKProxy factory = new JDKProxy();
//Proxy 为 InvocationHandler 实现类动态创建一个合乎某一接口的代理实例
OrderService orderService = (OrderService) factory.createProxyInstance(new OrderServiceImpl("JDK"));
// 由动静生成的代理对象来 orderService 代理执行程序
orderService.save(UUID.randomUUID(), "aoho");
}
}
---before invoke----
call save()办法,save:JDK
---after invoke----
Cglib 动静代理
cglib 是针对类来实现代理的,它会对指标类产生一个代理子类,通过办法拦挡技术对过滤父类的办法调用。代理子类须要实现 MethodInterceptor 接口
1. 被代理类,该类能够实现接口,也能够不实现接口
public class OrderManager {public void save(UUID orderId, String name) {System.out.println("call save()办法,save:" + name);
}
}
2. 代理类,实现 MethodInterceptor 接口,重写 intercept 办法
public class CGLibProxy implements MethodInterceptor {
// CGLib 须要代理的指标对象
private Object targetObject;
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
// 回调办法的参数为代理类对象 CglibProxy,最初加强指标类调用的是代理类对象 CglibProxy 中的 intercept 办法
enhancer.setCallback(this);
// 加强后的指标类
Object proxyObj = enhancer.create();
// 返回代理对象
return proxyObj;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
// 切面逻辑(advise),此处是在指标类代码执行之前
System.out.println("---before intercept----");
obj = method.invoke(targetObject, args);
System.out.println("---after intercept----");
return obj;
}
}
3. 创立代理类对象,通过代理类对象调用业务办法
public class AOPTest {public static void main(String[] args) {OrderManager order = (OrderManager) new CGLibProxy().createProxyObject(new OrderManager("aoho"));
order.save(UUID.randomUUID(), "CGLIB");
}
---before invoke----
call save()办法,save:CGLIB
---after invoke----
JDK 与 Cglib 动静代理比照?
1、JDK 动静代理只能代理实现了接口的类,没有实现接口的类不能实现 JDK 的动静代理;
2、Cglib 动静代理是针对类实现代理的,运行时动静生成被代理类的子类拦挡父类办法调用,因而不能代理申明为 final 类型的类和办法;
Spring 如何抉择两种代理模式的?
1、如果指标对象实现了接口,则默认采纳 JDK 动静代理;
2、如果指标对象没有实现接口,则应用 Cglib 代理;
3、如果指标对象实现了接口,但强制应用了 Cglib,则应用 Cglib 进行代理
咱们能够联合源码来看下,下面的抉择:
参考:
深刻了解 Spring AOP 的动静代理