結合 "Spring 後置處理器源碼" 和 "Spring Aware源碼" ,再來看下 Spring AOP 的源碼。 啟動 AOP 使用 @EnableAspectJAutoProxy 這個註解來啟用 AOP 的能力了。它使用 @Import 導入類 AspectJAutoProxyRegist ...
結合 Spring 後置處理器源碼 和 Spring Aware源碼 ,再來看下 Spring AOP 的源碼。
啟動 AOP
使用 @EnableAspectJAutoProxy 這個註解來啟用 AOP 的能力了。它使用 @Import 導入類 AspectJAutoProxyRegistrar,這個類實現了 ImportBeanDefinitionRegistrar,所以它會被 ConfigurationClassParser 掃描,並加入緩存中。然後 ConfigurationClassBeanDefinitionReader 從緩存中會拿到這個類,再執行其實現的方法 registerBeanDefinitions()。
AspectJAutoProxyRegistrar.registerBeanDefinitions() 源碼
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
上述方法又使用 AOP 配置工具類 AopConfigUtils 將 AnnotationAwareAspectJAutoProxyCreator 也註冊到 BeanFactory,其 name 為 org.springframework.aop.config.internalAutoProxyCreator。
下圖,展示了 AnnotationAwareAspectJAutoProxyCreator 的類繼承關係
可以看出來 AnnotationAwareAspectJAutoProxyCreator 就是 BeanPostProcessor 和 Aware,其頂層抽象類 AbstractAutoProxyCreator 實現它們的介面。
創建代理對象
Spring Aware源碼 中可知,BeanFactoryAware 實現類會在 invokeAwareMethods() 被回調 setBeanFactory() 方法,將 DefaultListableBeanFactory 註入給 AnnotationAwareAspectJAutoProxyCreator。
InstantiationAwareBeanPostProcessor 新增了後置處理器方法 postProcessBeforeInstantiation() 和 postProcessAfterInstantiation(),這兩個方法會在 Bean 初始化之前,也就是在 BeanPostProcessor 定義的方法之前先調用。
- postProcessBeforeInstantiation() 會在反射調用 Bean 的構造器之前調用。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 會返回一個代理對象,會執行 postProcessBeforeInstantiation()
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, mbdToUse, args);
}
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 從緩存獲取
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 判斷是否已經在 advisedBeans 緩存
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 判斷 Bean 是否是 Advice/Pointcut/Advisor/AopInfrastructureBean 這些不需要代理的基礎類型;或者是否 @Aspect 註解類
// 找到切麵類中的所有通知方法,判斷是否 AspectJPointcutAdvisor 類型,否則返回 false
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
return null;
}
- postProcessAfterInstantiation() 會在給屬性賦值的方法 populateBean() 中執行。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
// 屬性賦值,會執行 postProcessAfterInstantiation()
populateBean(beanName, mbd, instanceWrapper);
// 執行 BeanPostProcessor 的方法
return initializeBean(beanName, exposedObject, mbd);
}
- BeanPostProcessor 的方法是在 initializeBean() 中才執行的。其中 postProcessAfterInitialization() 方法會獲取切麵類的所有通知方法,利用動態代理技術,創建增強的代理對象(比如:
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
),同時會設置回調方法,完成後返回。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 包裝
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 包裝類
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 找到所有的候選通知方法
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 從候選通知方法找到可用於當前 Bean 的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 獲取所有的通知攔截器對象
Object[] specificInterceptors = eligibleAdvisors.toArray();
// 利用 AopProxy 來創建代理對象
// AopProxy 包含 JDK 和 CGLib 兩種實現
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
至此,動態代理對象以及創建完成了,容器中就會有這個增強後的代理對象,方法執行時,也就會利用這個代理對象來執行通知方法了。
執行代理對象
執行被代理的方法時,會被 CglibAopProxy 攔截器攔截,獲取這個方法的攔截器鏈。如果有攔截器鏈,則創建 CglibMethodInvocation 對象,執行 proceed(),即執行通知方法,最後返回 retVal,即方法的返回值;如果沒有攔截器鏈,則直接執行方法;
攔截器鏈實際上就是把方法攔截器放在 ArrayList 隊列中,第一個預設是 ExposeInvocationInterceptor,剩下的預設順序為 AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice、AspectJAfterAdvice、AspectJAroundAdvice、AspectJMethodBeforeAdvice。
proceed() 按照上面 ArrayList 中的順序遞歸調用,當遇到 AspectJAroundAdvice、AspectJMethodBeforeAdvice 類型的通知時,會利用反射直接執行它們的通知方法,其他類型通知不會立即執行,會等待遞歸返回之後再行調用 invoke() 方法。這樣,就能保證通知和方法的執行順序:
環繞通知執行 proceed() 前->前置通知->執行方法->環繞通知執行 proceed() 後->後置通知->返回通知->方法返回
總結
- @EnableAspectJAutoProxy 使用 @Import(AspectJAutoProxyRegistrar.class) 導入 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar。
- 容器刷新時,invokeBeanFactoryPostProcessors() 執行 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar.registerBeanDefinitions() 註冊 AnnotationAwareAspectJAutoProxyCreator 到 BeanFactory。
- AnnotationAwareAspectJAutoProxyCreator 實現了 InstantiationAwareBeanPostProcessor 和 BeanFactoryAware,在 registerBeanPostProcessors() 將其註冊到 BeanFactory,並且執行 invokeAwareMethods() 回調 (AbstractAdvisorAutoProxyCreator)BeanFactoryAware.setBeanFactory() 方法。
- finishBeanFactoryInitialization() 執行 (AnnotationAwareAspectJAutoProxyCreator)BeanPostProcessor.postProcessAfterInitialization(),找到切麵類及其切麵通知方法,使用動態代理技術(ObjenesisCglibAopProxy/JdkDynamicAopProxy),對切麵類進行增強,創建增強後的代理對象
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
。 - 執行被代理的方法時,會被 CglibAopProxy 的攔截器攔截,拿到方法的攔截器鏈,按順序遞歸調用,利用反射技術執行通知方法,以此實現不同通知的調用順序。