引
上一節(jié)分析了aspectj-autoproxy標簽的解析過程,并注冊了AnnotationAwareAspectJAutoProxyCreator。但是該類的作用是什么呢,看起來茫然無措,這時不妨查看一下類的繼承關系結構。
從上圖可以看到,AnnotationAwareAspectJAutoProxyCreator類實現了BeanPostProcessor接口,讀過之前的章節(jié)或者對bean的生命周期有所了解的同學一定知道,在bean實例化完成之前和完成之后分別會自動BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。
依次打開AnnotationAwareAspectJAutoProxyCreator的父類,在AbstractAutoProxyCreator類里,找到postProcessBeforeInitialization方法和postProcessAfterInitialization方法,開始分析。
1. postProcessBeforeInstantiation方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// 1、預處理判斷
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 判斷該類是否應被處理過
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 判斷beanClass是否需要被代理
// isInfrastructureClass-->判斷beanClass是否為AOP基礎類例如Advice(增強),Advisors(切面),Pointcut(切點)
// shouldSkip-->判斷beanClass是否指定了不需要代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
// 緩存找到的切面類信息
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
// 2、如果有自定義TargetSource的話,則在此創(chuàng)建代理
/**
* 自定義TargetSource示例:
* <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
* <property name="customTargetSourceCreators">
* <list>
* <bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/>
* </list>
* </property>
* </bean>
*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
postProcessBeforeInstantiation一共做了兩件事情
- 緩存切面類的信息
先判斷對應的beanClass是否為Aop的基礎類,如果是的話,直接緩存。
然后通過shouldSkip方法判斷beanClass是否需要被自動代理,如果不需要被自動代理的話,返回true,否則返回false。 - 判斷有無自定義TargetSource,如果有的話,則在此方法里創(chuàng)建代理
關于自定義TargetSource已經給出了一個簡單的實例,感興趣的同學可以自己debug代碼。
其中第一步的shouldSkip(beanClass, beanName)方法,看似簡單,其實這里面包含了非常復雜的業(yè)務邏輯處理?!ぜ?strong>增強的提取
2. shouldSkip方法簡析
/**
* 如果給定的bean不應該被認為是后處理器自動代理的,子類應該重寫這個方法以返回true。
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @return
*/
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 1、查找所有候選增強
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2、循環(huán)判斷所有的增強,如果增強是AspectJPointcutAdvisor的實例
// 并且其名稱與當前bean的名稱相同,則返回true,即該bean無需代理
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor
&& ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
該方法主邏輯很簡單,查找所有的候選增強并循環(huán)判斷當前beanName是否需要被代理,關鍵是findCandidateAdvisors()方法中獲取增強的過程。
/**
* AnnotationAwareAspectJAutoProxyCreator
* 查找所有候選增強方法
* @return
*/
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 1、從父類中獲取所有的增強
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 2、從當前BeanFactory中查找所有標記了@AspectJ的注解的bean,并返回增強注解集合
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
該方法也非常簡單:
- 從父類中獲取所有的增強
- 從當前BeanFactory中查找所有標記了@AspectJ的注解的bean,并返回增強注解集合
逐個對其進行分析:
3. findCandidateAdvisors方法分析
protected List<Advisor> findCandidateAdvisors() {
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* 從當前BeanFactory中尋找所有的增強bean,忽略FactoryBean和正在創(chuàng)建的bean
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @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.
// 獲取緩存的增強
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!
// 從當前BeanFactory中獲取所有類型為Advisor的bean
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory,
Advisor.class,
true,
false);
this.cachedAdvisorBeanNames = advisorNames;
}
// 當前BeanFactory中沒有類型為Advisor的bean則返回一個空的集合
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 循環(huán)所有獲取到的bean
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 跳過正在創(chuàng)建的增強
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 通過getBean方法獲取bean實例
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
// 跳過正在創(chuàng)建的增強
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
4. buildAspectJAdvisors方法分析
/**
* 在當前BeanFactory中查找AspectJ-annotated的注解信息,并返回增強集合
* 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.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
// 1、提取增強
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 1.1、獲取容器中的所有bean
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 1.2、循環(huán)所有的bean,并從切面類上提取增強
for (String beanName : beanNames) {
// 判斷該beanName是否符合條件
// 如果配置文件指定了<aop:include/>屬性,那么只有符合表達式條件的切面類的增強才會被提取
// 例如:配置<aop:include name="dogAspect"></aop:include>
// 那么只有dogAspect切面類的增強才會被提取
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;
}
// 如果beanType是一個切面類
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
/**
* 切面實例化模型簡介
*
* singleton: 即切面只會有一個實例;
* perthis : 每個切入點表達式匹配的連接點對應的AOP對象都會創(chuàng)建一個新切面實例;
* 使用@Aspect("perthis(切入點表達式)")指定切入點表達式;
* 例如: @Aspect("perthis(this(com.lyc.cn.v2.day04.aspectj.Dog))")
* pertarget: 每個切入點表達式匹配的連接點對應的目標對象都會創(chuàng)建一個新的切面實例;
* 使用@Aspect("pertarget(切入點表達式)")指定切入點表達式;
* 例如:
*
* 默認是singleton實例化模型,Schema風格只支持singleton實例化模型,而@AspectJ風格支持這三種實例化模型。
*/
// 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 {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
// perthis或pertarget實例化模型處理
else {
/**
* 注意:當使用perthis或pertarget屬性時,切面類不能是單例bean,否則會拋出下面的異常
* 例如:<bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="singleton"/>
* 則會報錯,應該為
* <bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="prototype"/>
*/
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;
}
}
}
// 2、返回從緩存中獲取提取到的增強方法
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;
}
其中的步驟在代碼里都標注的很清晰了,這里會涉及到一個切面實例化模型的概念,如果初看AOP的源碼,完全可以忽略該概念,把精力放在主線的分析上。其實該方法里大部分都是預處理、緩存、以及各種業(yè)務判斷,增強的提取工作交給了List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);。這也是我們要分析的重點。