上一篇我的博客《使用aop和注解实现日志记录》中提到了代理模式,那么这篇博客我们好好来理一下设计模式中的“代理模式”是如何在aop中设计和使用的。
1:首先,我先解释一下设计模式中“代理模式”的定义
什么是代理模式?
代理模式,也叫委托模式,其定义是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。它包含了三个角色:
Subject:抽象主题角色。可以是抽象类也可以是接口,是一个最普通的业务类型定义。
RealSubject:具体主题角色,也就是被代理的对象,是业务逻辑的具体执行者。
Proxy:代理主题角色。负责读具体主题角色的引用,通过真实角色的业务逻辑方法来实现抽象方法,并在前后可以附加自己的操作。
用类图来表示的话大概如下:
比如:我的上一篇我的博客《使用aop和注解实现日志记录》中,我的核心方法业务逻辑是执行addYaml方法,但是我需要在执行 addYaml方法前后输出关联的日志信息以方便后期出现异常时进行问题定位。
这时我可以直接把输出相关日志的代码加在addYaml方法中实现,也可以通过静态代理的方式单独写一个代理类实现addYaml方法,然后进行代理,具体实现见文章最后的参考文献。
考虑到相关的方法前后都要输出相关日志,并且方法众多,我不可能给所有的方法都实现一个代理类。所以Spring Framework框架利用Java反射+拦截的机制用动态代理的方式解决这一个问题。
Spring中AOP的实现采用的就是动态代理。
先简单放一张《使用aop和注解实现日志记录》中我debug时堆栈中的对象信息。如图我们可以看到methodInvocation={CglibAopProxy……},可以明确看到有使用CGLIB 动态代理。
而JDK 动态代理和 CGLIB 动态代理均是实现 Spring AOP 的基础。我们可以看下AOP的部分底层源码:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 判断目标类是否是接口或者目标类是否Proxy类型,若是则使用JDK动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用CGLIB的方式创建代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
// 上面条件都不满足就使用JDK的提供的代理方式生成代理对象
return new JdkDynamicAopProxy(config);
}
}
}
源码的判断逻辑并不难,主要是根据目标类是否是接口或者Proxy类型来判断使用哪种代理模式创建代理对象,使用的代理模式正是JDK动态代理和CGLIB 动态代理技术。
参考文献:
《设计模式:代理模式是什么,Spring AOP还和它有关系?》https://blog.csdn.net/yeyazhishang/article/details/95460654