代理模式 Proxy
当目标对象的功能不足以满足客户端的要求,系统为该对象创建一个代理对象,而代理对象可以增强原目标对象的功能。代理模式应用非常广泛,常见的有spring事务管理 为方法创建异步线程执行
代理模式分为静态代理和动态代理
静态代理
// 代理类与被代理类实现同一个接口,代理类持有被代理类引用
public interface Light {
// 照明
public void lighting();
}
// 吊灯
public class LampProxy implements Light{
private int power;
private Color color;
// 代理类持有被代理类的引用
private Lamp lamp;
public class LampProxy(Lamp lamp){
this.lamp = lamp
}
@Override
public void lighting(){
// 加大瓦数
incrPower();
// 变换色彩
changeColor();
// 发亮
lamp.lighting();
}
}
Lamp lamp = new LampProxy(lamp)
lamp.lighting();
动态代理 (JDK) 接口代理
JDK 代理通过生成代理类并持有被代理对象。代理对象需要实现被代理对象的接口,在实际调用被代理对象方法前后进行方法加强,然后通过反射进行方法调用所以实际执行者还是被代理类。
代理对象需要实现 InvocationHandler接口
publi class LampHandler implements InvocationHandler {
// 被代理对象
private Object target;
public void setTarget(Object target){
this.target = target;
}
// 执行动态代理对象的所有方法,都会被替换成执行如下方法
public Object invoke(Object proxy, Method method, Object[] args){
// do something before
Object result method.invoke(target, args)
// do something after
return result;
}
}
使用代理对象替换被代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
public class MyProxyFactory{
public static Object getProxy(Object target){
LampHandler lampHandler = new LampHandler();
// 为LampHandler设置Target值
handler.setTarget(target);
// 创建并返回一个动态代理
return Proxy.newProxyInstance(target.getclass.getClassLoader(), target.getClass.getInterfaces(), handeler)
}
}
动态代理 (CGLIB) 类代理
cglib动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法(cglib无法对final方法进行代理)。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
public class Lawyer {
/**
* 辩护
*/
void plead() {
System.out.println("为代理人辩护!");
}
}
public class LawyerInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
methodProxy.invokeSuper(o, objects);
return o;
}
}
public class LawyerTest {
public static void main(String[] args) {
// 有兴趣的同学可以看下CGLIB 动态生成的class文件源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/penglin/Desktop/");");
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(Lawyer.class);
//设置回调函数
enhancer.setCallback(new LawyerInterceptor());
Lawyer lawyer = (Lawyer) enhancer.create();
//调用代理类的eat方法
lawyer.plead();
}
}
使用aop动态代理模式的注解什么时候会失效
-
JDK代理模式中 被代理类中的方法在接口中未定义
-
CGLIB被代理类中被final/private关键字修饰的方法
-
相同实例方法内部调用
springboot 默认动态代理模式为 CGLIB
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true",
matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
// 获取properties 如果 spring.aop.proxy-target-class = false 则启用JDK 动态代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
// 获取properties 如果 spring.aop.proxy-target-class = true 则启用Cglib 动态代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}