Spring AOP是Spring的兩大基石之一,不瞭解其基礎概念的同窗能夠查看這兩篇文章AOP基本概念和修飾者模式和JDK Proxy。
若是從代碼執行角度來看,Spring AOP的執行過程分爲四大步驟:java
@Aspect
,@Async
等註解生成的實例,也能夠是程序員自定義的AbstractAdvisor
子類的實例。BeanPostProcessor
的postProcessAfterInitialization
方法,根據Advisor實例中切入點Pointcut
的定義,選擇出適合該目標對象的Advisor實例。Advice
邏輯。 因爲這四個步驟涉及的源碼量較大,一篇文章沒法直接徹底講解完,本篇文章只講解第一步Advisor
實例生成的源碼分析。接下來的文章咱們就依次講解一下後續步驟中比較關鍵的邏輯。程序員
Spring中有大量的機制都是經過AOP實現的,好比說@Async
的異步調用和@Transational
。此外,用戶也可使用@Aspect
註解定義切面或者直接繼承AbstractPointcutAdvisor
來提供切面邏輯。上述這些狀況下,AOP都會生成對應的Advisor實例。spring
咱們先來看一下Advisor的相關類圖。首先看一下org.aopalliance
包下的類圖。aopalliance是AOP組織下的公用包,用於AOP中方法加強和調用,至關於一個jsr標準,只有接口和異常,在AspectJ、Spring等AOP框架中使用。express
aopalliance定義了AOP的通知Advice
和鏈接點Joinpoint
接口,而且還有繼承上述接口的MethodInterceptor
和MethodInvocation
。這兩個類相信你們都很熟悉。編程
而後咱們來看一下Spring AOP中Advisor相關的類圖。Advisor是Spring AOP獨有的概念,比較重要的類有AbstractPointcutAdvisor
和InstantiationModelAwarePointcutAdvisor
。相關的講解都在圖中代表了,若是這張圖中的概念和類同窗們都熟識,那麼對AOP的瞭解就已經很深刻了。緩存
Advisor
實例 AOP生成Advisor實例的函數入口是AbstractAdvisorAutoProxyCreator
的findCandidateAdvisors
函數。架構
// AbstractAdvisorAutoProxyCreator.java 找出當前全部的Advisor protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } // AnnotationAwareAspectJAutoProxyCreator,是AbstractAdvisorAutoProxyCreator的子類 @Override protected List<Advisor> findCandidateAdvisors() { // 調用父類的findCandidateAdvisor函數,通常找出普通的直接 // 繼承Advisor接口的實例,好比說`@Async`所需的`AsyncAnnotationAdvisor` List<Advisor> advisors = super.findCandidateAdvisors(); // 爲AspectJ的切面構造Advisor,也就是說處理@Aspect修飾的類,生成上文中說的`InstantiationModelAwarePointcutAdvisor`實例 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
相關的ProxyCreator也有一個類體系,不過太過繁雜,並且重要性不大,咱們就先略過,直接將具體的類。由上邊代碼可知AbstractAdvisorAutoProxyCreator
的findCandidateAdvisors
函數是直接獲取Spring容器中的Advisor
實例,好比說AsyncAnnotationAdvisor
實例,或者說咱們自定義的AbstractPointcutAdvisor
的子類實例。AdvisorRetrievalHelper
的findAdvisorBeans
函數經過BeanFactory
的getBean
獲取了全部類型爲Advisor
的實例。框架
而AnnotationAwareAspectJAutoProxyCreator
看其類名就可知,是與AspectJ相關的建立器,用來獲取@Aspect
定義的Advisor實例,也就是InstantiationModelAwarePointcutAdvisor
實例。異步
接下去咱們看一下BeanFactoryAspectJAdvisorsBuilder
的buildAspectJAdvisors
函數,它根據@Aspect
修飾的切面實例生成對應的Advisor
實例。ide
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; // 第一次初始化,synchronized加雙次判斷,和經典單例模式的寫法同樣。 if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { // Spring源碼並無buildAspectJAdvisorsFirstly函數,爲了方便理解添加。 // 獲取aspectNames,建立Advisor實例,而且存入aspectFactoryCache緩存 return buildAspectJAdvisorsFirstly(); } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); // 遍歷aspectNames,依次獲取對應的Advisor實例,或者是MetadataAwareAspectInstanceFactory生成的Advisor實例 for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); // cache能夠取到實例,該Advisor是單例的 if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { // 取得Advisor對應的工廠類實例,再次生成Advisor實例,該Advisor是多實例的。 MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }
buildAspectJAdvisors
函數執行時分爲兩種狀況,第一個未初始化時,也就是aspectNames
爲null時,執行buildAspectJAdvisorsFirstly
進行第一次初始化,在這一過程當中生成切面名稱列表aspectBeanNames
和要返回的Advisor
列表,而且將生成的Advisor
實例放置到advisorsCache
中。
第二種狀況則是已經初始化後再次調用,遍歷aspectNames
,從advisorsCache
取出對應的Advisor
實例,或者從advisorsCache
取出Advisor對應的工廠類對象,再次生成Advisor
實例。
public List<Advisor> buildAspectJAdvisorsFirstly() { List<Advisor> advisors = new ArrayList<>(); List<String> aspectNames = new ArrayList<>(); // 調用BeanFactoryUtils獲取全部bean的名稱 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // 獲取對應名稱的bean實例 Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } /** * AbstractAspectJAdvisorFactory類的isAspect函數來判斷是否爲切面實例 * 判斷條件爲是否被@Aspect修飾或者是由AspectJ編程而來。 */ if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); // 切面的屬性爲單例模式 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 獲取一個切面中全部定義的Advisor實例。一個切面能夠定義多個Advisor。 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); // 單例模式,只須要將生成的Advisor添加到緩存 if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } // 多實例模式,須要保存工廠類,便於下一次再次生成Advisor實例。 else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; }
buildAspectJAdvisorsFirstly
函數的邏輯以下:
BeanFactoryUtils
獲取了BeanFactory中全部的BeanName,而後進而使用BeanFactory
獲取全部的Bean實例。ReflectiveAspectJAdvisorFactory
的isAspect
函數判斷該實例是否爲切面實例,也就是被@Aspect
註解修飾的實例。ReflectiveAspectJAdvisorFactory
,根據切面實例的定義來生成對應的多個Advisor
實例,而且將其加入到advisorsCache
中。 ReflectiveAspectJAdvisorFactory
的getAdvisors
函數會獲取@Aspect
修飾的實例中全部沒有被@Pointcut
修飾的方法,而後調用getAdvisor
函數,而且將這些方法做爲參數。
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; } // 生成Advisor實例 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); } private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 得到該函數上@Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing註解的信息 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); // 沒有上述註解,則直接返回 if (aspectJAnnotation == null) { return null; } AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // 得到註解信息中的切入點判斷表達式 ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory != null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; }
getAdvisor
函數就是根據做爲參數傳入的切面實例的方法上的註解來生成Advisor實例,也就是InstantiationModelAwarePointcutAdvisorImpl
對象。依據方法上的切入點表達式生成AspectJExpressionPointcut
。
咱們都知道PointcutAdvisor
實例中必然有一個Pointcut
和Advice
實例。修飾在方法上的註解包括:@Pointcut
, @Around
, @Before
, @After
, @AfterReturning
和@AfterThrowing
,因此InstantiationModelAwarePointcutAdvisorImpl
會依據不一樣的不一樣的註解生成不一樣的Advice
通知。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { // .... 省略成員變量的直接賦值 // 單例模式時 this.pointcut = this.declaredPointcut; this.lazy = false; // 按照註解解析 Advice this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); }
InstantiationModelAwarePointcutAdvisorImpl
的構造函數中會生成對應的Pointcut
和Advice
。instantiateAdvice
函數調用了ReflectiveAspectJAdvisorFactory
的getAdvice
函數。
// ReflectiveAspectJAdvisorFactory public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); // 獲取 Advice 註解 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 檢查是否爲AspectJ註解 if (!isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); } AbstractAspectJAdvice springAdvice; // 按照註解類型生成相應的 Advice 實現類 switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: // @Before 生成 AspectJMethodBeforeAdvice springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: // @After 生成 AspectJAfterAdvice springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: // @AfterReturning 生成 AspectJAfterAdvice springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: // @AfterThrowing 生成 AspectJAfterThrowingAdvice springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: // @Around 生成 AspectJAroundAdvice 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); } // 配置Advice springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); // 獲取方法的參數列表方法 String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { // 設置參數名稱 springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
至此,Spring AOP就獲取了容器中全部的Advisor
實例,下一步在每一個實例初始化完成後,根據這些Advisor
的Pointcut
切入點進行篩選,獲取合適的Advisor
實例,並生成代理實例。
Spring AOP後續文章很快就會更新,請你們繼續關注。