Spring原始碼分析:AOP分析(三)
個人扯淡部落格:http://blog.ztgreat.cn
前言
在上篇部落格中,分析了Spring Aop的Advice的實現過程,其中Spring對Advice 使用了介面卡模式,將Advice包裝成了Interceptor,在最後,我們通過Spring提供的介面,實現了PointCut,Advice ,Advisor,至此更加的明白了三者的關係。
在前面的配置中,對於每一個需要被代理的bean,我們都是通過手動配置Advisor,很顯然這是最原始的方式,當然這個從分析的角度出發也是最好分析的,今天我們稍微在那個高階一點,通過相關的配置,指定一些規則,讓Spring 自動的給我們代理需要被代理的bean,這樣就不再需要我們一個一個的配置了。
除錯程式碼
最好的分析方式,當然還是跟著原始碼來看看咯,當然個人覺得在什麼都不知曉的情況下,最好還是不要著眼於具體的每一行程式碼,一行一行的debug,這樣可能會被繞暈,我個人都是反覆先看幾篇,瞭解簡單流程後,對於比較混亂的地方,進行debug,然後再繼續看,最後在進行一次debug,測試,驗證。
說遠了,回到正題,對於除錯程式碼,我們還是延用前面最簡單的程式碼,這裡就重複貼出來了,在Spring原始碼分析:AOP分析(一) 中可以找到,程式碼也很簡單(userService
,beforeAdvice
)
XML配置
採用xml配置的主要原因,在於好分析。
<bean id="userService" class="com.study.spring.aop.UserServiceImpl"/> <!--advice--> <bean id="beforeAdvice" class="com.study.spring.aop.BeforeAdvice" /> <!--定義 advisor--> <bean id="userServiceAdivsor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="beforeAdvice"/> <property name="mappedName" value="add"/> </bean> <!--定義DefaultAdvisorAutoProxyCreator--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
簡要說明
前4行配置,這個就是簡單的配置我們需要被代理的bean,已經advice(增強)
對於這裡的advisor,採用的是Spring的NameMatchMethodPointcutAdvisor
,通過名字我們可以知道,這個是通過名稱來匹配的,當然還有其他的匹配方式,比如RegexpMethodPointcutAdvisor
正則匹配,這個匹配規則就要豐富的很多,為了簡單,當然我們還是採用NameMatchMethodPointcutAdvisor了。
在NameMatchMethodPointcutAdvisor 中,我們指定advice,以及需要被增強的方法(可以多個)。
最後我們在配置一個bean->DefaultAdvisorAutoProxyCreator
,這個bean 會自動的根據dvisor建立代理,今天的主角就是它啦。
執行結果
對於userService,如果呼叫add 方法,那麼就會執行的我們增強邏輯(即beforeAdvice),呼叫其它方法,則不會增強,好了,現在該我們的主角登場了。
DefaultAdvisorAutoProxyCreator
繼承體系
注:下圖的繼承關係,刪除了部分分支
我們可以發現,DefaultAdvisorAutoProxyCreator 是一個 BeanPostProcessor,既然是BeanPostProcessor 那這個就好辦了,前面我們已經分析IOC的流程了,在refresh中 會註冊BeanPostProcessor 。
回顧IOC refresh
AbstractApplicationContext -> refresh:
@Override
public void refresh() throws BeansException, IllegalStateException {
// 同步操作
synchronized (this.startupShutdownMonitor) {
// 準備工作,記錄下容器的啟動時間、標記"已啟動"狀態
prepareRefresh();
// 這步在前面我們分析過,這步主要將配置檔案就會解析成一個個 Bean 定義,註冊到 BeanFactory 中,
// 但是此時 Bean 還沒有初始化,只是配置資訊都提取出來了,
//這步中有 customizeBeanFactory 方法,具體在後面介紹
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設定 BeanFactory 的類載入器,新增幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
//這個後面會具體介紹
prepareBeanFactory(beanFactory);
try {
// 如果 Bean 實現了BeanFactoryPostProcessor介面,
// 那麼在容器初始化以後,Spring 會負責呼叫裡面的 postProcessBeanFactory 方法。
// 這裡是提供給子類的擴充套件點,到這裡的時候,所有的 Bean 都載入、註冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候新增一些特殊的 BeanFactoryPostProcessor 的實現類或做點什麼事
postProcessBeanFactory(beanFactory);
// 呼叫 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別
// 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之後得到執行。
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,不是重點,忽略
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器,忽略
initApplicationEventMulticaster();
// 模板方法
// 具體的子類可以在這裡做一些特殊操作
onRefresh();
// 註冊事件監聽器,監聽器需要實現 ApplicationListener 介面,忽略
registerListeners();
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最後,廣播事件,ApplicationContext 初始化完成
finishRefresh();
}
//...省略後續程式碼
}
}
在註冊BeanPostProcessor 的時候,肯定是會例項化bean的,那麼BeanPostProcessor的介面在什麼時候執行呢?
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
回顧IOC 初始化bean
在 Spring原始碼分析:IOC容器初始化(二) 中我們分析過,為了方便,這裡再貼下程式碼:
AbstractAutowireCapableBeanFactory ->initializeBean:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 如果 bean 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 介面,回撥
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 處理 bean 中定義的 init-method,
// 或者如果 bean 實現了 InitializingBean 介面,呼叫 afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回撥
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可想而知,Spring AOP 會在 IOC 容器建立 bean 例項(這裡特指 userService)的最後對 bean 進行處理(BeanPostProcessor 呼叫)。其實就是在這一步進行代理增強。
AbstractAutoProxyCreator
我們回過頭來,DefaultAdvisorAutoProxyCreator 的繼承結構中,postProcessAfterInitialization() 方法在其父類 AbstractAutoProxyCreator 這一層被覆寫了:
postProcessAfterInitialization
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
二話不說 繼續往裡看 wrapIfNecessary方法:
wrapIfNecessary
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;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 返回匹配當前 bean 的所有的 advisor、advice、interceptor
// 對於本文的例子,"userService",會得到 一個 NameMatchMethodPointcutAdvisor
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;
}
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),這個方法將得到所有的可用於攔截當前 bean 的advisor、advice、interceptor。
拿到interceptor後,就可以建立代理物件了。
createProxy
我們繼續往下看 createProxy 方法:
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 建立 ProxyFactory 例項
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//我們介紹過,如果希望使用 CGLIB 來代理介面,可以配置
// proxyTargetClass="true",這樣不管有沒有介面,都使用 CGLIB 來生成代理:
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 1. 有介面的,呼叫:proxyFactory.addInterface(ifc);
// 2. 沒有介面的,呼叫:proxyFactory.setProxyTargetClass(true);
// 兩者在具體代理實現上策略不同(jdk proxy;cglib proxy)
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 這個方法會返回匹配了當前 bean 的 advisors 陣列
// 對於本文的例子,"userService"到這邊的時候會返回 NameMatchMethodPointcutAdvisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//通過 proxyFactory 獲取代理
return proxyFactory.getProxy(getProxyClassLoader());
}
我們看到,這個方法主要是在內部建立了一個 ProxyFactory 的例項,通過這個例項來建立代理: getProxy(classLoader)
。
看一下 proxyFactory.getProxy(…)方法:
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
這個方法很簡單,建立AOP代理(預設工廠是 DefaultAopProxyFactory
),然後建立代理物件,到這裡就和我們在
Spring原始碼分析:AOP分析(一),中分析的內容接上了,後續的建立代理過程在前面已經分析了,這裡就不在繼續了。
至此,關於DefaultAdvisorAutoProxyCreator的部分我們就分析完了。
總結
在本文,我們通過DefaultAdvisorAutoProxyCreator 自動建立bean代理,隨後通過DefaultAdvisorAutoProxyCreator 的繼承關係,我們知道了DefaultAdvisorAutoProxyCreator 是一個 BeanPostProcessor,接著我們簡單的回顧了IOC中關於BeanPostProcessor 的註冊以及在建立bean後執行 BeanPostProcessor 回撥,最終我們知道在 BeanPostProcessor 的回撥方法中,建立代理bean,具體的邏輯在DefaultAdvisorAutoProxyCreator 的父類 AbstractAutoProxyCreator中,其主要邏輯便是獲取該bean的interceptor,然後建立AOPFactory來建立代理,而AOPFactory 預設是 DefaultAopProxyFactory,在建立代理過程中,會根據配置或者類的資訊,選擇採用cglib 代理還是jdk代理,這部分內容,在AOP 分析(一)中我們已經分析過了,至此,關於AOP的分析基本可以告一段落了,整個過程,並沒有徹頭徹尾的分析Spring AOP的實現。
在Spring原始碼分析:AOP分析(一) 中我們分析了jdk代理和cglib代理的實現原理,同時我們從ProxyFactoryBean 入手,知道了,Spring 建立代理的流程。
在 Spring原始碼分析:AOP分析之Advice 中,分析了Spring如何把advice(增強)應用到代理物件上的。
在本文,知道如何通過Spring 自動的為我們需要的代理的物件,建立代理,並指定過濾規則。
當然Spring AOP 中還有很多 高階的用法,但是目前這些對我們理解AOP應該足夠了,如果有需要,再進行深入瞭解分析。