内容整理自《精通Spring+4.x++企业应用开发实战 Chap7》
代理
静态代理 :代理类已存在
动态代理:代理类动态生成
JDK动态代理:
基于java.lang.reflect包,主要涉及类Proxy, InvocationHandler。
被代理的类需要实现某个接口。因为jdk动态代理是基于接口的。
主要代码:
public class BusinessImpl emplements BusinessService{
public void doSomething(){
//业务实现
}
}
/**
* 编织器
*/
public class AdvisorHandler implements InvocationHandler{
private Object target;
AdvisorHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args){
//业务前增强
Object obj = method.invoke(target, args);//业务实现
//业务后增强
return obj;
}
}
/**
* 业务调用
*/
public class TestProxy{
public static void main(String[] args){
BusinessService target = new BusinessImpl();
AdvisorHandler handler = new AdvisorHandler(target);
BusinessService proxy = (BusinessService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.doSomething();
}
}
CGLib动态代理:
基于底层字节码技术,为需要增强的类创建子类,在子类中使用拦截技术拦截所有父类方法的调用并添加增强代码;
对比jdk动态代理,不需要类必须实现接口才能创建动态代理;
主要代码:
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();//通过字节码技术创建子类实例
}
/* 拦截父类中所有的方法 */
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable{
//业务前增强
Object result = proxy.invokeSuper(obj,args);
//业务后增强
return result;
}
}
/**
* 测试代码
*/
public class TestProxy{
public static void main(String[] args){
CglibProxy proxy = new CglibProxy();
BusinessImpl bussiness = (BusinessImpl) proxy.getProxy(BusinessImpl.class);
business.doSomething();
}
}
对比:
对于单例的代理对象或者具有实例池的代理,因为无需频繁创建代理对象,所以比较适合CGLib,因为它的性能高于jdk;
如果频繁的创建代理对象,因为CGLib创建代理对象花费的时间远高于JDK动态代理,最好使用JDK动态代理;
缺陷:
- 目标类中所有方法都会被增强;
- 通过硬编码,只能在方法前后增强;
- 手工编写代理实例的创建,为不同类创建代理,需要创建不同的代理实例;
解决: 参考 spring AOP;