上文中提到了 AOP 建立代理等等的具體操做都是在 AnnotationAwareAspectAutoProxyCreator 類中來成的,經過上文的自動註冊,下面讓咱們看 AnnotationAwareAspectAutoProxyCreator 是如何工做的,首先是 AnnotationAwareAspectAutoProxyCreator 的繼承關係圖:
java
而後是 AnnotationAwareAspectAutoProxyCreator 的層次結構圖:
web
這裏須要特別注意的是 BeanPostProcessor 接口,咱們知道實際運用中,若是你須要對項目中的 Bean 進行代理,在 Spring 的 xml 的配置一個 BeanPostProcessor 就行。由此,咱們能夠知道 AnnotationAwareAspectAutoProxyCreator 實現代理也是經過 BeanPostProcessor 接口來完成的,因此咱們對於 AOP 邏輯分析也是由 BeanPostProcessor 實例化前的 postProcessAfterInitialization 方法開始,而 AnnotationAwareAspectAutoProxyCreator 的 postProcessAfterInitialization 具體實現是在其父類 AbstractAutoProxyCreator 中完成的。咱們對 AOP 邏輯的分析也由此開始。
正則表達式
AbstractAutoProxyCreator.javaexpress
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { // 根據給定的 bean 的 class 和 name 構建出個 key,格式:beanClassName_beanName Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 若是它適合被代理,則須要封裝指定 bean。 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 是否已經處理過 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } // 無需加強 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 給定的 bean 類是否表明一個基礎設施類,基礎設施類不該代理,或者配置了指定 bean 不須要自動代理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 若是存在加強方法則建立代理 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 若是獲取到了加強則須要針對加強建立代理 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 建立代理 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
以上兩個方法構成了建立代理的雛形,固然,開始前還有些判斷工做。而建立代理的核心邏輯部分是在 AbstractAutoProxyCreator 類中完成的,而建立代理前的準備工做主要分爲兩步:(1)獲取加強方法或者加強器。(2)根據獲取的加強進行代理。下面是 AbstractAutoProxyCreator 的時序圖:數組
結合時序圖,咱們知道真正建立代理地方是從 getAdvicesAndAdvisorsForBean 開始的。雖然看起來很簡單,但其實每一步都有大量複雜的邏輯。但在分析源碼前,咱們必須先對加強以及其具體邏輯有所瞭解。app
Advice(也翻做 通知)定義了鏈接點作什麼,爲切面加強提供了織入的接口。在 Spring AOP 中,它主要描述 Spring AOP 圍繞方法調用而注入的切面行爲。Advice 是 AOP 聯盟定義的一個接口,具體的接口定義在 org.aopalliance.aop.Advice 中。在 Spring AOP 的實現中,使用了這個統一接口,並經過這個接口,爲 AOP 切面加強的注入功能作了更多的細化和擴展,好比前面提到的具體通知類型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等。做爲 Spring AOP 定義的接口類,具體的切面加強能夠經過這些接口集成到 AOP 框架中去發揮做用。對於這些接口類,下面是他的主要接口繼承圖:
框架
下面是 Advice 接口繼承的層次圖:
ide
看一個程序的具體設計思路沒有比看接口來的更直接的了,下面咱們就從第一個 BeforeAdvice 的繼承接口 MethodBeforeAdvice 開始(BeforeAdvice 裏沒有任何東西)函數
MthodInterceptor.java源碼分析
public interface MethodInterceptor extends Interceptor { void before(Method method, Object[] args, Object target) throws Throwable; }
明顯可以看出這是一個回調函數,他的具體參數有:Method 對象,這個參數是目標方法的反射對象,Object[]對象數組,這個對象數組中包含沒辦法發的輸入參數。而咱們根據繼承關係看他的具體實現類 AspectJMethodBeforeAdvice。
AspectJMethodBeforeAdvice.java
@Override public void before(Method method, Object[] args, Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); }
AbstractAspectJAdvice.java
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex)); } protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterTypes().length == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(this.aspectJAdviceMethod); // 激活加強 return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); } catch (IllegalArgumentException ex) { throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } }
invokeAdviceMethodWithGivenArgs 方法中的 aspectJAdviceMethod 正是對於前置加強的方法,在這裏實行了調用。下面是 AfterAdvice 的繼承接口 AfterReturningAdvice 接口:
AfterReturningAdvice.java
public interface AfterReturningAdvice extends AfterAdvice { void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; }
而 AfterReturningAdvice 接口的核心邏輯是在其實現父類 AspectJAfterReturningAdvice 中完成的。
AspectJAfterReturningAdvice.java
@Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { if (shouldInvokeOnReturnValueOf(method, returnValue)) { invokeAdviceMethod(getJoinPointMatch(), returnValue, null); } }
後面的和 BeforeAdvice 同樣。根據分析咱們能夠知道 BeforeAdvice 和 AfterAdvice。儘管,這兩個加強行爲一致,旦由於它實現的 AOP 通知不一樣,因此就被 AOP 編織到不一樣的調用場合中了。而其餘的加強基本思路都是如此,這裏就不展開了。
Pointcut(關注點,也稱 切點)用於決定 Advice 加強做用於哪一個鏈接點,也就是說經過 Pointcut 來定義須要加強的方法集合,而這些集合的選取能夠經過必定的規則來完成,例如:這些須要加強的地方能夠由某個正則表達式來進行標識,或根據某個方法名來進行匹配等。下面是 Pointcut 的層次結構圖:
下面是 Pointcut 接口:
Pointcut.java
public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; }
經過 Pointcut 接口的基本定義咱們能夠看到,須要返回一個 MethodMatcher。對於 Point 的匹配判斷功能,具體是由這個返回的 MethodMatcher 來完成的,也就是說,有這個 MethodMatcher 來判斷是否須要對當前方法調用進行加強或者配置應用。我接着對 MethodMatcher 接口進行分析:
MethodMatcher.java
public interface MethodMatcher { boolean matches(Method method, Class<?> targetClass); boolean isRuntime(); boolean matches(Method method, Class<?> targetClass, Object[] args); MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; }
經過閱讀註釋咱們知道了 Pointcut 的核心邏輯是在 matches 方法中完成的,我就以經過方法名匹配的 NameMatchMetchMethodPointcut 類的 matches 方法來講明:
NameMatchMetchMethodPointcut.java
@Override public boolean matches(Method method, Class<?> targetClass) { for (String mappedName : this.mappedNames) { if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) { return true; } } return false; }
從源碼咱們看到他的實現是很是簡單的,匹配條件就是方法名相同或者方法名匹配。
Advisor(通知器)用一個對象將對目標方法的切面加強設計(Advice)和關注點的設計(Pointcut)結合起來。下面是 Advisor 接口的層次繼承圖:
這是一個 Advisor 接口的設計,咱們從中能夠看出經過 Advisor,能夠定義應該使用哪一個加強而且在哪一個關注點使用它,也就是經過 Advisor,把 Advice 和 Pointcut 結合起來,這個結合爲使用 IOC 容器配置 AOP應用,提供了便利。下面是 Advisor 接口:
Advisor.java
public interface Advisor { Advice getAdvice(); boolean isPerInstance(); }
下面咱們以一個 Advisor 的實現(DefaultPointcutAdvisor)爲例,進而瞭解 Advisor 的工做原理。
DefaultPointcutAdvisor.java
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable { private Pointcut pointcut = Pointcut.TRUE; public DefaultPointcutAdvisor() { } public DefaultPointcutAdvisor(Advice advice) { this(Pointcut.TRUE, advice); } public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) { this.pointcut = pointcut; setAdvice(advice); } public void setPointcut(Pointcut pointcut) { this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE); } @Override public Pointcut getPointcut() { return this.pointcut; } @Override public String toString() { return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]"; } }
這個類主要職責是 Pointcut 的設置或者獲取,在 DefaultPointcutAdvisor 中,Pointcut 默認被設置爲 Pointcut.True,這個 Pointcut.True 接口被定義爲 Pointcut True = TruePointcut.INSTANCE。而關於 Advice 部分的設置與獲取是由其父類 AbstractGenericPointcutAdvisor 來完成的。
下面就讓咱們回到源碼分析,前面已經提到了通知器,這裏就不冗述了,他的主要做用是用來整合切面加強設計(Advice)和切入點設計(Pointcut)。而對於指定 bean 的加強方法的獲取,通常包含獲取全部加強以及尋找全部加強中適合於 bean 的加強並應用這兩個步驟。
AnnotationAwareAspectAutoProxyCreator.java
@Override protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
從源碼看,這兩個步驟必定是由 findCandidateAdvisors 和 findAdvisorsThatCanApply 來完成。還有值得注意的是,若是沒法找到對應的通知器便會返回 DO_NOT_PROXY(null)。
——水門(2016年3月於杭州)