[Spring]AnnotationAwareAspectJAu
AnnotationAwareAspectJAutoProxyCreator职能
AnnotationAwareAspectJAutoProxyCreator
是用来处理被@AspectJ
注解标注的切面类和Spring Advisors
的.
其中,Spring Advisors
的处理规则遵循AbstractAdvisorAutoProxyCreator
中建立的规则.
UML
UML我们从类图可以看到,AnnotationAwareAspectJAutoProxyCreator
的组成结构还是稍微复杂的。下面我们来过一下其中比较重要的接口.
- AopInfrastructureBean: 实现该接口的类会被标记为Spring内部的基础类,Spring AOP并不会对这类型的Bean进行代理.
- 与Aware相关的接口: 通过此类接口获取容器的BeanFactory和ClassLoader.
-
ProxyConfig: 用于创建代理的配置类,以确保所有代理创建者都具有一致的属性.内部可配置
proxyTargetClass
、exposeProxy
、optimize
等属性 -
ProxyProcessorSupport: 具有代理处理器通用功能的基类,此外,还特地提供了ClassLoader的管理和
evaluateProxyInterfaces
方法,ProxyFactory可以通过evaluateProxyInterfaces
方法获取给定bean类上的接口. - InstantiationAwareBeanPostProcessor: Spring AOP中会在实例化前判断是否需要创建用户自定义的代理类,进而影响Spring Bean的声明周期.
- SmartInstantiationAwareBeanPostProcessor: 重量级方法->getEarlyBeanReference,当Spring Bean发生循环依赖的时候,决定是否要将创建代理的时机提前.
- BeanPostProcessor: AbstractAutoProxyCreator会在postProcessAfterInitialization中来解析当前Bean是否需要代理,正常的Bean是在此处进行代理的,当执行到这步的时候,通常Spring Bean已经完成实例化、初始化了。
-
AbstractAutoProxyCreator: 继承了
ProxyProcessorSupport
和SmartInstantiationAwareBeanPostProcessor
,是Spring AOP的代理创建器,将匹配代理的地方交由子类去实现.同时,它还是getEarlyBeanReference
方法的实现者. -
AbstractAdvisorAutoProxyCreator: 提供为每个Bean选择特定的advisor进行代理的功能,提供
findCandidateAdvisors
和getAdvicesAndAdvisorsForBean
方法用于寻找候选的advisors和为bean匹配advisors. -
AspectJAwareAdvisorAutoProxyCreator: 提供了对advisors进行排序的功能,同时为了兼容XML的切面配置解析,也保留了
shouldSkip
- AnnotationAwareAspectJAutoProxyCreator: Spring用于解析切面类,将需要执行的通知方法转化成Spring Advisor.
Spring Advisor
Spring中的Advisor接口是Spring AOP的基础接口,一个Advisor可以持有一个pointcut和一个AOP advice.Spring AOP正是通过将被AspectJ
标注的类中的不同Advice解析成Advisor调用链来执行切面逻辑的。
Advised-操作Advisor
public interface Advised extends TargetClassAware {
// 返回当前的advised配置是否被冻结
boolean isFrozen();
// 代理完整的目标类而不是指定的接口
boolean isProxyTargetClass();
// 返回由AOP代理代理的接口。
// 将不包括目标类别,也可以将其作为代理。
Class<?>[] getProxiedInterfaces();
// 确定是否代理给定的接口
boolean isInterfaceProxied(Class<?> intf);
// 更改此建议对象使用的TargetSource。
// 仅在未冻结配置的情况下有效。
void setTargetSource(TargetSource targetSource);
// 返回此Advised对象使用的TargetSource。
TargetSource getTargetSource();
// 设置代理是否应由AOP框架公开为ThreadLocal以便通过AopContext类进行检索。
// 默认值为false,以实现最佳性能。
void setExposeProxy(boolean exposeProxy);
// 当前代理工厂是是否将代理类引用通过ThrealLocal管理起来.
boolean isExposeProxy();
// 获取当前代理的所有advisors
Advisor[] getAdvisors();
// 向当前proxy的advisor调用链追加一个advisor
void addAdvisor(Advisor advisor) throws AopConfigException;
// 向当前proxy的advisor调用链中的某个位置插入一个advisor
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
// 移除给定的advisor
boolean removeAdvisor(Advisor advisor);
// 移除某个位置中的advisor
void removeAdvisor(int index) throws AopConfigException;
// 获取当前advisor在执行链中的位置. -1代表没有任何的advisor
int indexOf(Advisor advisor);
// 替代某个advisor
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
// 向advice的拦截链中添加给定的AOP Alliance advice
void addAdvice(Advice advice) throws AopConfigException;
void addAdvice(int pos, Advice advice) throws AopConfigException;
boolean removeAdvice(Advice advice);
int indexOf(Advice advice);
// 返回AOP代理的配置项。
String toProxyConfigString();
}
TargetSource
Spring AOP并不是直接代理目标类,而是通过代理TargetSource接口进而实现动态代理.
简单来说即: Spring AOP->TargetSource->targetObject
- UML
加载切面类并解析advisor
- AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 从缓存中获取当前BeanClass的Class对象,在advisedBeans这个Map中,以class为key
// 同时,该class还充当proxyTypes这个Map中的key
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 如果当前类已经被动态代理了,不进行任何操作
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 当前beanClass是否实现Advice、Pointcut、Advisor、AopInfrastructureBean
// 是否需要跳过解析
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 如果当前beanClass存在用户自定义的TargetSource,则进行代理
// 在Spring AOP中,动态代理并不是直接代理target对象的,而是通过代理TargetSource来间接代理target对象
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取当前bean的advisors
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 创建代理类
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
- 需要过滤已经创建过动态代理的类,
advisedBeans
这个Map便是缓存已经被Spring AOP处理过的BeanClass.- 其中
isInfrastructureClass
会过滤掉Spring AOP框架内部的基类,同时会识别当前是否标注了@AspectJ
与被ajc
编译器所编译.- 如果当前用户自定义实现了TargetSource接口,那么AbstractAutoProxyCreator会为用户自定义的TargetSource创建代理.
我们深入
isInfrastructureClass
这个方法看看,step into!
isInfrastructureClass-忽略Spring AOP的基础服务类
- org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
@Override
protected boolean isInfrastructureClass(Class<?> beanClass) {
return (super.isInfrastructureClass(beanClass) ||
(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}
父类中的AbstractAutoProxyCreator
调用了AnnotationAwareAspectJAutoProxyCreator
中的isInfrastructureClass
,这里有2个判断:
- 调用父类的
isInfrastructureClass
,返回true
则直接中断.
父类执行isInfrastructureClass
的逻辑为:当前beanClass是否实现Advice
、Pointcut
、Advisor
、AopInfrastructureBean
. - 判断当前
beanClass
是否为切面类.isApsect
的逻辑比较简单:beanClass上是否标注了@Aspect
注解并且没有被ajc
编译器编译过.
- org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
public boolean isAspect(Class<?> clazz) {
// 类上是否标注@Aspect并且没有被ajc编译器编译过
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
shouldSkip-将切面类解析成advisor
- org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 查找候选的advisors
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
shouldSkip是Spring AOP构建advisor的入口,spring会在每次执行
postProcessBeforeInstantiation
的时候,解析每个advisor,解析完成后将advisors进行缓存,进而判断当前的beanClass和beanName是否已经解析完毕. 下面,我们来看看findCandidateAdvisors
这个方法做了什么,step into.
- org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 添加根据超类规则找到的所有Spring advisors.从层级关系我们可以知道,
// AspectJAwareAdvisorAutoProxyCreator提供对XML或者实现接口的AOP配置解析
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 注解驱动的AOP切面解析类解析
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
这里面
findCandidateAdvisors
分成了两条线路:
- 调用父类
AspectJAwareAdvisorAutoProxyCreator#finCandidateAdvisors
提供对XML或者实现接口的AOP配置解析成advisor列表.- 解析注解形式的Aspect成advisor列表.
最后,都添加进advisor列表中.
解析advisor类型的bean.
- org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans
return this.advisorRetrievalHelper.findAdvisorBeans();
}
这里进行了一个helper的委托,真正执行者为
BeanFactoryAdvisorRetrievalHelperAdapter#findAdvisorBeans
.
- org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
/**
* <p>Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.</p>
* 在当前beanFactory中查找所有有资格的advisor.<br>
* 对FactoryBean和正在创建中的bean不生效 <br>
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// 从缓存中获取容器中所有的advisor bean的名字数组
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 如果缓存中没有,那么从容器中以及其父容器中分析得到所有的advisor bean的名称
// BeanFactoryUtils.beanNamesForTypeIncludingAncestors此处是找到类型为advisor的bean
// 注意,spring不推荐在此处实例化factoryBeans,因为spring需要保留所有未初始化的常规类
// 以使自动代理创建者对其应用!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
// 回种缓存
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
// 是否为合适的bean,提供给用户自定义实现,默认返回true
if (isEligibleBean(name)) {
// 创建中的bean会被忽略,beanPostProcessor是每次加载bean都会触发的钩子
// 所以在下次进来时,可能当前正在创建的bean已经被创建好了
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 根据advisorName获取advisor实例
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
// 省略处理异常细节
}
}
}
}
return advisors;
}
首先,会尝试从缓存中获取
advisorNames
数组,里面存储了容器中所有的advisor bean的名字.如果无法从缓存中获取,那么重新加载符合条件的advisorNames
数组,回种缓存.这里要注意:BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);
中,传入的是Advisor
类型.,也就是寻找类型为Advisor
的beanName,并非所有beanName.遍历
advisorNames
数组,对符合条件的advisor进行getBean
操作,然后添加进advisors
集合返回.
buildAspectJAdvisors-解析被@Aspect注解标记的类
/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.<br>
* 1. 从容器获取所有的beanName集合 <br>
* 2. 找到其中被@AspectJ标注的类 <br>
* 3. 解析Aspect类,将其转化成advisors <br>
* 4. 将result加入cache中 <br>
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
// 获取所有aspect类的beanName
List<String> aspectNames = this.aspectBeanNames;
// 如果aspectNames为空,那么进行加载
if (aspectNames == null) {
// 双重检查锁,防止多线程之间产生并发访问
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
// 保存切面名称的集合
aspectNames = new ArrayList<>();
// 获取所有的beanName
// BeanFactoryUtils.beanNamesForTypeIncludingAncestors传入的type为Object
// 也就说查找所有的bean,spring在这里使用了缓存,避免每次加载消耗性能
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历所有的beanName
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 必须小心,不要急于实例化bean,因为在这种情况下,它们将由Spring容器缓存,但不会被编织。
// 获取bean的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.isAspect
// 筛选出当前class是否标记了@Apsect注解
if (this.advisorFactory.isAspect(beanType)) {
// 将当前的beanName加入到aspectNames这个缓存中
aspectNames.add(beanName);
// 获取当前beanClass的aspect元数据
// AjType中包含了切面的详细数据
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 获取切面的种类,通常为singleton
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// Aspect中的advice+pointcut可以组成一个个advisor
// 举个例子,before、after、around每个都会搭配pointcut组成advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 如果bean是单例,存到单例缓存中
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 否则将工厂和beanName缓存
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
方法比较长,但是总体的脉络我们还是可以总结一下:
- 尝试从缓存获取所有的aspectNames集合.如果缓存找不到,重新加载.执行的方法又是
BeanFactoryUtils.beanNamesForTypeIncludingAncestors
,只不过这次传入的类型是Object.class
,也就是说,获取的是所有的beanNames.- 遍历beanNames数组,通过name获取type,然后判断当前类是否为Aspect.也就是被
@Aspect
注解所标记.- 如果是Aspect,构建
AspectMetadata
,AspectMetadata
中保存了AjType
,这是AspectJ
框架的产物,通过它可以快速获取当前类的pointcut
和advice
等.Spring AOP正是借助AspectJ来获取切面类的信息的.此外,AspectJ还提供了很多切面模型种类,通常,我们的切面类都是为singleton
-单例.- 调用
ReflectiveAspectJAdvisorFactory#getAdvisors
来解析Aspect类,进而解析出List<Advisor>
.
- org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取Aspect类的class
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取Aspect的类名
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校验切面类,不可以为抽象类,需标记@Aspect
// spring aop 不支持percflow、percflowbelow种类的aspect
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 使用装饰器模式包装MetadataAwareAspectInstanceFactory
// 包装器类重写了getAspectInstance方法,并且保证当前的factory在使用时才进行加载(缓存)
// 正如名字的意义一般 lazy singleton instance
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取aspect切面类中的所有方法,会过滤掉被@Pointcut标记的方法
// 获取到的List<Method>按照Around, Before, After, AfterReturning, AfterThrowing的顺序排序
for (Method method : getAdvisorMethods(aspectClass)) {
// 将方法解析成advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
getAdvisors就是我们关注的注解切面类解析逻辑了:
- 首先从
aspectInstanceFactory
中获取元数据进而获取切面类型和切面名称,随后对切面类进行校验-切面类不可以为抽象类,需标记@Aspect,同时,spring aop 不支持percflow、percflowbelow种类的aspect.- 使用装饰器模式包装
MetadataAwareAspectInstanceFactory
来懒加载切面类实例.- 获取当前类中标记
@Pointcut
注解外所有的Method集合,获取到的List<Method>按照Around
,Before
,After
,AfterReturning
,AfterThrowing
的顺序排序.- 遍历每一个Method,将符合条件的方法解析成
advisor
实例.- 检查是否有属于introduction的成员,如果有便进行解析(@DeclareParents).
- 将解析完成的每一个advisor添加到返回的结果集中.
- org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 验证aspectClass的合法性
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 在切面的方法上构建pointcut表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 实例化切面中的advice对象
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
- 校验aspectClass的合法性,这个validate是复用的,跟上述的方法一致,逻辑就不重复讲了.
- 根据当前的adviceMethod与aspectClass构建出AspectJExpressionPointcut实例.它是一个pointcut表达式的实例.里面对AspectJ框架的表达式原语进行了部分的支持(11种).
- 通过getPointcut()获取到切点表达式之后,接下来就可以实例化adivce然后构建出advisor了,因为一个advisor = pointcut+advice.我们接着看
InstantiationModelAwarePointcutAdvisorImpl
这个方法是如何实例化advice的.
- org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#InstantiationModelAwarePointcutAdvisorImpl
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 当前的pointcut表达式
this.declaredPointcut = declaredPointcut;
// 切面Class
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
// advice方法名称
this.methodName = aspectJAdviceMethod.getName();
// 方法参数类型
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
// 方法实例
this.aspectJAdviceMethod = aspectJAdviceMethod;
// aspectJ的advisor工厂
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
// aspectJ实例工厂
this.aspectInstanceFactory = aspectInstanceFactory;
// 切面顺序
this.declarationOrder = declarationOrder;
// 切面类名称
this.aspectName = aspectName;
// 是否需要延时加载
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
// singleton模型的aspect
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 将切面中的advice进行实例化
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
InstantiationModelAwarePointcutAdvisorImpl
是advisor的子类.在这个构造函数内对传入的属性进行了设置,然后根据当前的切面模型决定是否需要延迟加载.- 通常我们的切面类都是singleton的,所有会直接执行
instantiateAdvice
.
- org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
这里直接转发给了
this.aspectJAdvisorFactory.getAdvice
这个方法.继续跟踪.
- org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 获取切面类Class
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 校验合法性
validate(candidateAspectClass);
// 获取切面方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 使用switch来判断当前advice类型
switch (aspectJAnnotation.getAnnotationType()) {
// pointcut不解析
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
// around类型的Advice
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// before类型的Advice
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// after类型的Advice
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// afterReturning类型的Advice
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
// afterThrowing类型的Advice
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
// 设置AspectName、DeclarationOrder,为后期执行调用链的时候做准备
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
- 解析Advice之前,Spring又又又对切面类进行了一次校验.
- 解析Advice,根据当前方法上的注解匹配对应的advice.例如:around、before、after、afterReturning、afterThrowing.
- 为advice实例配置切面名称、参数名称、声明顺序等.
OK,至此,Advice实例就被解析成功了.此时的
InstantiationModelAwarePointcutAdvisorImpl
成员属性中携带了pointcut+advice.
梳理加载Advisors的整体流程.
流程图扩展阅读
【小家Spring】Spring AOP中@Pointcut切入点表达式最全面使用介绍
【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)