前言
Spring AOP是整个Spring框架中最重要的内容之一。为了更好的深入查看它的原理,这篇文章主要是把它在关键位置使用到的一些常用类进行打点、解释一波,有助于我们去看源代码的时候变得更加的轻松、流畅
Spring AOP相关类、组件内容庞大。此处只会介绍一些最为常用的概念进行分析~~~
1、ProxyConfig
AOP配置类:用于创建代理的配置的父类,以确保所有代理创建者具有一致的属性。 它有五个属性,解释如下:
public class ProxyConfig implements Serializable {
// 标记是否直接对目标类进行代理,而不是通过接口产生代理
private boolean proxyTargetClass = false;
// 标记是否对代理进行优化。true:那么在生成代理对象之后,如果对代理配置进行了修改,已经创建的代理对象也不会获取修改之后的代理配置。
// 如果exposeProxy设置为true,即使optimize为true也会被忽略。
private boolean optimize = false;
// 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
//Advised接口其实就代表了被代理的对象(此接口是Spring AOP提供,它提供了方法可以对代理进行操作,比如移除一个切面之类的),它持有了代理对象的一些属性,通过它可以对生成的代理对象的一些属性进行人为干预
// 默认情况,我们可以这么完 Advised target = (Advised) context.getBean("opaqueTest"); 从而就可以对该代理持有的一些属性进行干预勒 若此值为true,就不能这么玩了
boolean opaque = false;
//标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
//当一个代理对象需要调用它【自己】的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
boolean exposeProxy = false;
//标记是否需要冻结代理对象,即在代理对象生成之后,是否允许对其进行修改,默认为false.
// 当我们不希望调用方修改转换成Advised对象之后的代理对象时,就可以设置为true 给冻结上即可
private boolean frozen = false;
}
2、Pointcut
这个类位于 org.springframework.aop 包中,它的作用就是定义切面的匹配点。(简单的说就是我去切哪些类、哪些方法…) 在 Spring Aop 中匹配的点主要是 class 与 method 这两个方面, 分别为ClassFilter 与 MethodFilter
// 由 ClassFilter 与 MethodMatcher 组成的 pointcut
public interface Pointcut {
// 类过滤器, 可以知道哪些类需要拦截
ClassFilter getClassFilter();
// 方法匹配器, 可以知道哪些方法需要拦截
MethodMatcher getMethodMatcher();
// 匹配所有对象的 Pointcut
Pointcut TRUE = TruePointcut.INSTANCE;
}
在 Spring 中主要有以下几个类,介绍如下:
NameMatchMethodPointcut
:通过刚发名进行精确匹配的。 (PS: 其中 ClassFilter = ClassFilter.TRUE)ControlFlowPointcut
:根据在当前线程的堆栈信息中的方法名来决定是否切入某个方法(效率较低)ComposablePointcut
:组合模式的 Pointcut, 主要分成两种: 1.组合中所有都匹配算成功 2. 组合中都不匹配才算成功JdkRegexpMethodPointcut
:通过 正则表达式来匹配方法(PS: ClassFilter.TRUE)AspectJExpressionPointcut
:通过 AspectJ 包中的组件进行方法的匹配(切点表达式)TransactionAttributeSourcePointcut
:通过 TransactionAttributeSource 在 类的方法上提取事务注解的属性 @Transactional 来判断是否匹配, 提取到则说明匹配, 提取不到则说明匹配不成功AnnotationJCacheOperationSource
:支持JSR107的cache相关注解的支持
上述中的 TransactionAttributeSourcePointcut 其实就是Spring注解式事务的 Pointcut。通过匹配方法上 @Transactional 标签来确定方法是否匹配;(事务篇会分析它的源码)
3、Advice
Advice: 建议忠告, 劝告, 通知。它其实最开始是 aopalliance 包中的一个空接口, 接口的存在主要是为了标示对应类为 Advice;
在Spring Aop 中 Advice 其实表示的是在 Pointcut 点上应该执行的方法。而这些方法可以在目标方法之前、之后、包裹、抛出异常等等任何地方执行。
Advice: 其主要分成两类:普通advice 与Interceptor/MethodInterceptor:
3.1普通Advice
MethodBeforeAdvice
:在目标方法之前执行,主要实现有:AspectJMethodBeoreAdvice
:这是通过解析被@Before
注解注释的方法时解析成的Advice
AfterReturningAdvice
:在切面方法执行后(这里的执行后指不向外抛异常, 否则的话就应该是 AspectJAfterThrowingAdvice 这种 Advice) 主要实现有:
AspectJAfterAdvice
:解析 AspectJ 中的@After
注解来生成的 Advice(PS: 在java中的实现其实就是在 finally 方法中调用以下对应要执行的方法)AspectJAfterReturningAdvice
:解析 AspectJ 中的@AfterReturning
属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就将不执行)AspectJAfterThrowingAdvice
:解析 AspectJ 中的@AfterThrowing
属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就执行)
AspectJAroundAdvice
:将执行类 MethodInvocation(MethodInvocation其实就是Pointcut) 进行包裹起来, 并控制其执行的 Advice (其中 Jdk中中 Proxy 使用ReflectiveMethodInvocation, 而 Cglib 则使用 CglibMethodInvocation)
注意,注意,注意:在Proxy中最终执行的其实都是MethodInterceptor,因此这些Advice最终都是交给 AdvisorAdapter -> 将 advice 适配成 MethodInterceptor
3.2 MethodInterceptor
ExposeInvocationInterceptor:将当前 MethodInvocation 放到当前线程对应的 ThreadLoadMap里面的, 这是一个默认的 Interceptor, 在
AspectJAwareAdvisorAutoProxy获取何时的 Advisor 时会调用自己的 extendAdvisors 方法, 从而将 ExposeInvocationInterceptor 方法执行链表的第一位。
AfterReturningAdviceInterceptor:这个类其实就是将 AfterReturningAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 AfterReturningAdviceAdapter
MethodBeforeAdviceInterceptor:这个类其实就是将 MethodBeforeAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 MethodBeforeAdviceAdapter
ThrowsAdviceInterceptor:这个类其实就是将 ThrowsAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是ThrowsAdviceAdapter
TransactionInterceptor:这个类就是大名鼎鼎的注解式事务的工具类, 这个类通过获取注解在方法上的 @Transactional 注解的信息来决定是否开启事务的 MethodInterceptor (PS: 在注解式事务编程中将详细叙述)
1、无论通过aop命名空间/AspectJ注解注释的方法, 其最终都将解析成对应的 Advice
2、所有解析的 Advice 最终都将适配成 MethodInterceptor, 并在 JdkDynamicAopProxy/CglibAopProxy中进行统一调用
4、Advisor
Advisor 其实它就是 Pointcut 与 Advice 的组合, Advice 是执行的方法, 而要知道方法何时执行, 则 Advice 必需与 Pointcut 组合在一起, 这就诞生了 Advisor 这个类
打个比方:
Advice = 代理逻辑
PointCut = 切点
Advisor = Advice+PointCut
4.1 PointcutAdvisor: 我们在 Spring 中常用的 Advisor, 包含一个 Pointcut 与一个 advice
4.2 AspectJPointcutAdvisor: 这个是 Spring 解析 aop 命名空间时生成的 Advisor(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 对于这个类的解析是在 ConfigBeanDefinitionParser
4.3 InstantiationModelAwarePointcutAdvisorImpl: 这个Advisor是在Spring解析被 @AspectJ注解注释的类时生成的 Advisor, 而这个 Advisor中的 Pointcut与Advice都是由 ReflectiveAspectJAdvisorFactory 来解析生成的(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 解析的步骤是: AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors() -> BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisor() 最终生成了 InstantiationModelAwarePointcutAdvisorImpl (当然包括里面的 Pointcut 与 advice 也都是由 ReflectiveAspectJAdvisorFactory 解析生成的)
4.4 TransactionAttributeSourceAdvisor: 一个基于 MethodInterceptor(其实是 TransactionInterceptor)与 TransactionAttributeSourcePointcut 的Advisor, 而这个类最常与 TransactionProxyFactoryBean使用
4.5 DefaultPointcutAdvisor: 最常用的 Advisor, 在使用编程式aop时, 很多时候会将 Advice / MethodInterceptor 转换成 DefaultPointcutAdvisor
4.6 NameMatchMethodPointcutAdvisor: 这个是在使用 NameMatchPointcutAdvisor时创建的 Advisor, 主要是通过 方法名来匹配是否执行 Advice
4.7 RegexpMethodPointcutAdvisor: 基于正则表达式来匹配 Pointcut 的 Advisor, 其中的 Pointcut 默认是 JdkRegexpMethodPointcut
4.8 Spring 中解析 aop:advisor 时生成的 Advisor, 见 ConfigBeanDefinitionParser.parseAdvisor
4.9 BeanFactoryTransactionAttributeSourceAdvisor: 在注解式事务编程时, 主要是由 BeanFactoryTransactionAttributeSourceAdvisor, AnnotationTransactionAttributeSource, TransactionInterceptor 组合起来进行事务的操作(PS: AnnotationTransactionAttributeSource 主要是解析方法上的 @Transactional注解, TransactionInterceptor 是个 MethodInterceptor, 是正真操作事务的地方, 而BeanFactoryTransactionAttributeSourceAdvisor 其实起着组合它们的作用); <- 与之相似的还有 BeanFactoryCacheOperationSourceAdvisor
5、Advised
Advised: 已经被建议的对。
它的主要实现,就是面向我们创建代理的,非常实用:
ProxyFactory: 这个类通过构造函数中的 proxyInterface/interceptor/targetSource 来创建代理对象(这个类是编程式 AOP 中最常用的对象)
ProxyFactoryBean: 这个类是基于 FactoryBean 的 Proxy创建形式, 其通过代理的 Interface, targetSource 与指定的 interceptorNames 来创建对应的AopProxy, 最后生成对应的代理对象
AspectJProxyFactory: 将一个被 @Aspect 注解标示的类丢入其中, 变创建了对应的代理对象 (这个类现在已经很少用了。 但是@Aspect方式常用哦)
6、TargetSource
TargetSource:其实是动态代理作用的对象
HotSwappableTargetSource: 进行线程安全的热切换到对另外一个对象实施动态代理操作
AbstractPoolingTargetSource: 每次进行生成动态代理对象时都返回一个新的对象(比如内部实现类CommonsPool2TargetSource就是例子,但它依赖于common-pool2包)
ThreadLocalTargetSource: 为每个进行请求的线程维护一个对象的 TargetSource
SingletonTargetSource: 最普遍最基本的单例 TargetSource, 在 Spring 中生成动态代理对象, 一般都是用这个 TargetSource
4、ProxyCreatorSupport
这个类应该很熟了,我们之前介绍过的三大创建代理对象的工厂ProxyFactoryBean、ProxyFactory、AspectJProxyFactory都是继承自此类的
ProxyCreatorSupport继承AdvisedSupport,主要提供了createAopProxy方法用来得到用来生成代理对象的AopProxy对象:
public class ProxyCreatorSupport extends AdvisedSupport {
// new了一个aopProxyFactory
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 由此可议看出,它还是委托给了`AopProxyFactory`去做这件事~~~ 它的实现类为:DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
}
//DefaultAopProxyFactory#createAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 对代理进行优化 或者 直接采用CGLIB动态代理 或者
//config.isOptimize()与config.isProxyTargetClass()默认返回都是false
// 需要优化 强制cglib 没有实现接口等都会进入这里面来
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.");
}
// 倘若目标Class本身就是个接口,或者它已经是个JDK得代理类(Proxy的子类。所有的JDK代理类都是此类的子类),那还是用JDK的动态代理吧
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 实用CGLIB代理方式 ObjenesisCglibAopProxy是CglibAopProxy的子类。Spring4.0之后提供的
//
return new ObjenesisCglibAopProxy(config);
}
// 否则(一般都是有实现接口) 都会采用JDK得动态代理
else {
return new JdkDynamicAopProxy(config);
}
}
// 如果它没有实现过接口(ifcs.length == ) 或者 仅仅实现了一个接口,但是呢这个接口却是SpringProxy类型的 那就返回false
// 总体来说,就是看看这个cofnig有没有实现过靠谱的、可以用的接口
// SpringProxy:一个标记接口。Spring AOP产生的所有的代理类 都是它的子类~~
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
Advised
Advice: 通知拦截器
Advisor: 通知 + 切入点的适配器
Advised: 包含所有的Advised 和 Advice
该接口用于保存一个代理的相关配置。比如保存了这个代理相关的拦截器、通知、增强器等等。
所有的代理对象都实现了该接口(我们就能够通过一个代理对象获取这个代理对象怎么被代理出来的相关信息)
不管是JDKproxy,还是cglib proxy,代理出来的对象都实现了org.springframework.aop.framework.Advised接口;
————————————————
版权声明:本文为CSDN博主「方向盘(YourBatman)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/f641385712/article/details/88925478