在前面Spring AOP中如何为Bean创建代理?一文中我们看到创建代理前首先要获取到Advisor设置给ProxyFactory,之后才可进行代理的创建。那么容器中的Advisor是如何实例化并注册的?
这个入口是在AbstractAutoProxyCreator
的postProcessBeforeInstantiation
方法中
【1】前置流程
如下图所示,在AbstractApplicationContext的refresh
方法中会触发registerBeanPostProcessors(beanFactory);
进行Bean后置处理器的注册。
而在AbstractAutowireCapableBeanFactory
的createBean过程中,会触发resolveBeforeInstantiation(beanName, mbdToUse);
,那么这里就会触发applyBeanPostProcessorsBeforeInstantiation
。
AbstractAutowireCapableBeanFactory的applyBeanPostProcessorsBeforeInstantiation方法如下所示。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
这里会判断BeanPostProcessor 是否为InstantiationAwareBeanPostProcessor
,如果是,则调用其postProcessBeforeInstantiation
方法。
InstantiationAwareBeanPostProcessor
是BeanPostProcessor的一个子接口,在bean的属性设置或autowire触发前增加before-instantiation和after-instantiation回调。通常用于抑制特定目标bean的默认实例化,例如创建具有特殊TargetSources的代理(池目标、延迟初始化目标等),或实现其他注入策略,如字段注入。
如下所示是其子类实现,这里我们主要分析AbstractAutoProxyCreator。
如下图所示,AbstractAutoProxyCreator的postProcessBeforeInstantiation会首先对bean进行判断。isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)
,前者用来判断是否为基础类,后置用来判断是否需要直接跳过。当前这只是语义含义,实际上isInfrastructureClass用来判断当前bean是否为Advice、Pointcut、Advisor、AopInfrastructureBean或者(标注了Aspect注解但是bean的field不是以ajc$
开头)。
我们看下shouldSkip方法。这里会调用AspectJAwareAdvisorAutoProxyCreator的shouldSkip方法,如下所示。
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
//super.shouldSkip(beanClass, beanName); AbstractAutoProxyCreator#shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
很显然,advisor就是从findCandidateAdvisors方法得到的。
【2】得到Advisor
结合前面流程,这里会走到AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
首先调用父类的findCandidateAdvisors方法,然后使用BeanFactoryAspectJAdvisorsBuilderAdapter创建AspectJAdvisor。
① super.findCandidateAdvisors();
这里是AbstractAdvisorAutoProxyCreator的findCandidateAdvisors方法。
//AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
// advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelperAdapter;
我们跟踪看一下advisorRetrievalHelper是如何找到Advisor的。
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// 从缓存里面获取
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 如internalTransactionAdvisor
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) {
// 这里默认返回true
if (isEligibleBean(name)) {
// 如果是正在创建的,则跳过
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 从容器中获取Bean
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
// ....
throw ex;
}
}
}
}
return advisors;
}
总结来讲该方法就是从容器中找Advisor,如果正在创建则跳过否则就获取到然后返回。
② aspectJAdvisorsBuilder.buildAspectJAdvisors
BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法如下所示。我们的切片被包装成Advisor就是在这里实现的。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 获取到所有的Bean,本文这里有460个
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
//AnnotationAwareAspectJAutoProxyCreator.isEligibleAspectBean进行判断,默认返回true
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.
// 获取beanTYPE
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 如果当前Bean标注了Aspect注解 且未被ajc编译
if (this.advisorFactory.isAspect(beanType)) {
// 放到aspectNames中-包含单例和非单例
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 默认就是SINGLETON
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 如果是单例则放入缓存
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 否则放入aspectFactoryCache
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));
}
}
}
// 重新给aspectBeanNames 赋值
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;
}
这里大概分为三种情况:
- 如果
List<String> aspectNames
为null,则进行初始化; - 如果
List<String> aspectNames
为空,则直接返回空列表; - 否则则尝试从advisorsCache或者advisorFactory获取advisors
那么在第一次是一定为null的,这里会从容器中获取到(标注了Aspect注解 且未被ajc编译的bean),如我们自己定义的logAspect。最终会通过this.advisorFactory.getAdvisors(factory)
得到Advisor。
那么这里List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
就是核心部分。
③ ReflectiveAspectJAdvisorFactory.getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 得到切片类型与名称
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//进行校验 PerClauseKind.PERCFLOW PerClauseKind.PERCFLOWBELOW 是否有注解Aspect
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 进行包装,使其只能实例化一次
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 得到AdvisorMethod,即不包含Pointcut的方法
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.
// PerClauseKind.PERTARGET PerClauseKind.PERTHIS PerClauseKind.PERTYPEWITHIN才会进入
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 引入通知中,尝试将每一个Field 包装为一个Advisor
for (Field field : aspectClass.getDeclaredFields()) {
// 这里针对的是DeclareParents 会创建DeclareParentsAdvisor
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
如上代码所示,这里首先获取切面类中未标注Pointcut注解的方法,然后实例化得到InstantiationModelAwarePointcutAdvisorImpl这样一个Advisor。
然后判断aspect是否需要懒加载,如果是则实例化SyntheticInstantiationAdvisor放入advisors的第一个位置。
最后对引入通知进行处理,拿到那些标注了DeclareParents 注解的filed,得到相应的DeclareParentsAdvisor放入advisors。
至此就完成了advisors 的查找。我们可以跟踪看一下getAdvisor和getDeclareParentsAdvisor方法。
getAdvisor
如下所示,首先进行校验然后获取AspectJExpressionPointcut ,如果不为null则实例化InstantiationModelAwarePointcutAdvisorImpl。这个也是我们在Spring AOP中如何为Bean创建代理?看到的。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
在实例化InstantiationModelAwarePointcutAdvisorImpl,还会对Advice进行实例化。如下所示在ReflectiveAspectJAdvisorFactory的方法中会拿到方法的AspectJAnnotation,根据其AnnotationType分别创建Advice。
// ReflectiveAspectJAdvisorFactory#getAdvice
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
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;
// 根据注解的类型创建对应的Advice
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
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...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
AnnotationType | Advice |
AtPointcut | null |
AtAround | AspectJAroundAdvice |
AtBefore | AspectJMethodBeforeAdvice |
AtAfter | AspectJAfterAdvice |
AtAfterReturning | AspectJAfterReturningAdvice |
AtAfterThrowing | AspectJAfterThrowingAdvice |
到这里,我们自定义的logAspect如何成为一个Advisor就清晰了。