概要
過度
我們前面介紹了對<aop:aspectj-autoproxy />標簽的解析過程,其實整體就做了一件事:創(chuàng)建一個后處理器并注冊。
本文我們主要介紹這個后處理器的工作原理。當然我們關(guān)注的重點是AOP相關(guān)的處理邏輯。
內(nèi)容簡介
結(jié)合我們之前了解的BeanFactory邏輯,了解此后處理器的工作邏輯。
對此后處理器創(chuàng)建AOP的邏輯進行詳細分析,包括:
- 找出所有注冊的增強器
- 針對要實例化的Bean選擇合適增強器
- 利用選出的合適的增強器創(chuàng)建動態(tài)代理
所屬環(huán)節(jié)
針對Bean生成動態(tài)代理
上下環(huán)節(jié)
上文:解析<aop:aspectj-autoproxy />節(jié)點
下文:Spring構(gòu)建的動態(tài)代理對象的工作原理
源碼解析
入口
我們上面講到解析標簽最終會導(dǎo)致AnnotationAwareAspectJAutoProxyCreator的注冊,這個類的繼承關(guān)系如下:

emmmm,又是一個繼承關(guān)系超級復(fù)雜的類,我們不再像前面學(xué)習(xí)BeanFactory時對每個類的角色、功能一一介紹了,我們把主要注意力集中在調(diào)用上面,這樣能讓我們思路清晰。
這里很容易發(fā)現(xiàn)AbstractAutoProxyCreator繼承了SmartInstantiationAwareBeanPostProcessor。這里應(yīng)該對BeanPostProcessor的主要處理邏輯有實現(xiàn)。
在擴展中,我們對擊中Bean的后處理器做了介紹。根據(jù)我們在擴展中的介紹,我們確認進行AOP動態(tài)代理創(chuàng)建的主要有三個地方:
postProcessBeforeInstantiationgetEarlyBeanReferencepostProcessAfterInitialization
其中第一種情況涉及短路,第二、第三種不涉及。而第一種段路但是會繼續(xù)手動調(diào)用postProcessAfterInitialization。所以實際調(diào)用的搭配方案是:
- 1,3
- 2,3
我們依次介紹三個調(diào)用方法,最后再整合看。我們先介紹一下基本的數(shù)據(jù)結(jié)構(gòu),方便后續(xù)代碼理解:
基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)
// 這個里面存的是通過 TargetSourceCreator 創(chuàng)建的 Bean 實例,不走 Spring 的創(chuàng)建實例、填值、初始化、提前暴露啥的,直接
// 一步走到最后的調(diào)用初始化之后的后處理器
private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 這個是配合 BeanFactory 進行解決循環(huán)依賴時提供的
// key: 計算得到的 cacheKey
// value: 是完成創(chuàng)建實例后得到的地址。還沒進行填值、初始化啥的
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
// 這個是將已經(jīng)完成代理創(chuàng)建的對象進行緩存
// key: 計算得到的cacheKey
// value: 代理之后得到的 Class
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
// 已經(jīng)增強的 Bean 的 map ,key 是根據(jù) beanName 生成的。 value 是這個 bean 已經(jīng)增強的原因:
// False 表示經(jīng)過之前的判斷,此 Bean 不需要增強。
// True 表示經(jīng)過之前的判斷,此 Bean 需要增強
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
四個屬性。
前兩個屬性分別對應(yīng)postProcessBeforeInstantiation和getEarlyBeanReference的實現(xiàn)。
后兩個屬性是做緩存以加快執(zhí)行效率。
postProcessBeforeInstantiation
我們先上代碼:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
// TODO targetSourcedBeans 中沒有針對這個 Bean 的緩存??????
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {//TODO 之前對此類 Bean 做過判斷
return null;
}
// 1. AOP配置的基礎(chǔ)類【不需進行AOP】
// 2. 子類自行定義一個判斷條件,將自己不想進行代理的類摘出去
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.
// 這里看一下,我們是不是配置了對應(yīng)的 TargetSourceCreator 來生成此類實例,如果配置了的話就直接走配置生成可用的目標實例
// 緩存創(chuàng)建的實例,然后在這里創(chuàng)建完成代理,不再走 Spring 的創(chuàng)建實例、屬性填充、初始化啥的操作了
//
// 這里主要是提供給使用者一個短路 Spring 基礎(chǔ)流程的機會,方便進行定制
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
// 存起來,表示下次處理 beanName ,直接走 TargetSourceCreator 并創(chuàng)建代理
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 得到我們配置的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 根據(jù)我們配置的 Advisor 創(chuàng)建代理對象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// TODO 緩存一下我們創(chuàng)建的代理類【這里不清楚有啥用】
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;// 短路
}
return null;
}
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
// We can't create fancy target sources for directly registered singletons.
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
if (ts != null) {
// Found a matching TargetSource.
if (logger.isDebugEnabled()) {
logger.debug("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
// No custom TargetSource found.
return null;
}
思路如下:

上面的思路是有點亂的,你只需要明白一點就可以了,這個函數(shù)的職責(zé)是嘗試借助TargetSourceCreator完成實例構(gòu)建,如果可以就可以短路操作,如果不行就走正常創(chuàng)建。這里面的一大堆判斷也是在推斷這個 Bean 是否之前做過這種判斷,有沒有保存好的判斷結(jié)果。
有兩個函數(shù)里封裝了我們的核心操作:
getAdvicesAndAdvisorsForBeancreateProxy
職責(zé)我們大概能猜到,具體的實現(xiàn)思路我們后面統(tǒng)一介紹。
getEarlyBeanReference
先上代碼:
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean); // 這里的 Bean 是完成創(chuàng)建實例后得到的地址。還沒進行填值、初始化啥的
return wrapIfNecessary(bean, beanName, cacheKey);
//TODO 這里提前進行了包裝,如果是jdk動態(tài)代理,后面在注入時怎么玩????,看看代理之后會不會影響 getter/setter函數(shù)
}
這里思路很簡單,因為實例已經(jīng)存在了,所以我們做緩存,然后根據(jù)情況創(chuàng)建代理即可。其中wrapIfNecessary方法后面詳細介紹。
postProcessAfterInitialization
貼代碼:
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
*
* @see #getAdvicesAndAdvisorsForBean
*/
// 如果要處理的 bean 實例被子類標識為需要代理的,就通過配置的攔截器創(chuàng)建代理
//
// 注意,這里的用詞是攔截器,因為是通過回調(diào)完成的調(diào)用。過濾器 Filter 是和 servlet 容器切合到一起的,
// 是 tomcat 的東西
//
// 這里是將通過 Spring 創(chuàng)建實例、完成添值、初始化完成的對象實例或者前面postProcessBeforeInstantiation()短路
// 得到的完善的實例,在這里將需要進行代理的進行創(chuàng)建代理
//
// 注意,這里需要判斷是否已經(jīng)代理過,別在 postProcessBeforeInstantiation() 創(chuàng)建一次代理,這里再創(chuàng)建一次
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
// TODO 這里后面重新過一下 Spring 創(chuàng)建 Bean 實例的步驟,傳進來的 beanName 是 alias 還是帶 & 的還是單純的 beanId
// TODO 如果不是單純的 beanId ,這里可能會出錯
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 這里意味著前面通過這個提前拿到的地址。在調(diào)用 postProcessAfterInitialization() 包裹時發(fā)現(xiàn)傳進來的
// 已經(jīng)和最開始的不一樣了。那就重新根據(jù)情況看是否要創(chuàng)建代理
// TODO 這里能看出來和最開始暴露出去的不一樣了,估計解決循環(huán)依賴是否成功只有依賴一下兩種情況是否恰好發(fā)生:
// 1. 沒有任何 Bean 引用了提前暴露出去的Bean
// 2. 在后面的 getEarlyBeanReference() 的處理過程中有操作繼續(xù)包裹導(dǎo)致這里的不一致
// TODO 其實這里想多了,上面的都是建立在假設(shè) earlyProxyReferences 就是暴露出去的對象,但是這里可以把它理解成一個記錄是否提前創(chuàng)建代理的記錄
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
思路很簡單,還是委托給wrapIfNecessary根據(jù)情況創(chuàng)建代理。只是之前可能做了提前暴露,用earlyProxyReferences緩存協(xié)助判斷看能否少走一步,加快構(gòu)造速度。
動態(tài)代理創(chuàng)建內(nèi)部邏輯記錄
wrapIfNecessary
上面我們對三個后處理的鉤子做了一些介紹,最后我們發(fā)現(xiàn)動態(tài)代理的創(chuàng)建基本委托給了wrapIfNecessary,當然也有更細致的委托,這里我們從這里入手對動態(tài)代理介紹,根據(jù)我先擼過一次的經(jīng)驗來說,從這里入手會把上面依賴的函數(shù)都過一遍。
直接放代碼:
// 如果這個 Bean 需要被代理,就代理一下
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// this.targetSourcedBeans.contains(beanName) 表示此 beanName 對應(yīng)的 bean 沒有走正經(jīng) Spring 創(chuàng)建實例的過程
// 直接搞定了。
// TODO 這種創(chuàng)建方式貌似不走AOP的東西
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 此 cacheKey 【通過 bean 實例得出】 之前做過判斷,根據(jù)之前的判斷是不用代理的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果滿足以下條件,則不對 bean 進行代理
// 1. 此類是基礎(chǔ)類【配置代理相關(guān)的配置類】
// 2. 或者根據(jù)用戶自定義的邏輯,不對它進行代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);// 這里做了緩存,方便有重復(fù)判斷時加快速度
return bean;
}
// Create proxy if we have advice.
// 得到 bean 對應(yīng)的增強方法,如果有需要增強的方法,則創(chuàng)建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);// 直接放進去,方便后續(xù)判斷
// 已經(jīng)確定要創(chuàng)建代理,將創(chuàng)建工作進行委托
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// TODO 看一下這個緩存是怎么做的??代理臨時生成的類可以復(fù)用嗎??
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 已經(jīng)確定不用創(chuàng)建代理,緩存一下結(jié)果,方便后面的判斷
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
思路如下:

我們主要介紹兩個函數(shù)即可:
getAdvicesAndAdvisorsForBeancreateProxy
正好是我們最開始的postProcessBeforeInstantiation依賴的兩個。
getAdvicesAndAdvisorsForBean
直接上代碼:
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 繼續(xù)委托
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
// 如果沒查到就返回特定值,方便判斷
// TODO 感覺這種設(shè)計方法還是不太好的,一個返回值有了多種解讀語意,應(yīng)該是 Spring 為了接口簡潔做的一些妥協(xié)
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 獲得所有的增強器
// 找出來,然后實例化
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到這個 bean 可以用的增強
// 這里涉及針對 aop 篩選類、方法的東西
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 這里留一個鉤子,方便子類根據(jù)自己的需要進行增強器定制
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
還是老套路,繼續(xù)向外委托,本函數(shù)只做基礎(chǔ)的記錄和轉(zhuǎn)換。所以就一下子貼了兩個函數(shù)上去。整體思路還是比較清楚的:
- 先拿到所有的增強器
- 根據(jù)Bean篩選出可用的增強器
- 返回
我們接下來依次看這兩步的操作,先看第一步:拿到所有的增強器
// 返回 auto-proxy 中配置的所有的增強器
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// 委托給專門負責(zé)增強器檢索的類
return this.advisorRetrievalHelper.findAdvisorBeans();
}
我們看findAdvisorBeans:
// 找到當前 BeanFactory 中所有的增強器
// TODO 注意,因為聲明增強器的方法太多了,我們挑通用邏輯。
// 不支持 FactoryBean。。。。正常人打@Aspect注解也不會專門搞個 FactoryBean , 保持類的功能純粹吧
// TODO 不支持正在實例化的bean。。。。這個再看
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!
// 得到實現(xiàn)了 Advisor 接口的所有 beanId
// 注意,這里傳了 false ,不會對 FactoryBean 進行初始化后再比
// TODO 存疑,我們打的是 @Aspect 注解,什么時候轉(zhuǎn)化成對應(yīng)的 Advisor 類型的Bean了
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
// 沒有定義增強器,直接返回
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 等等,這個注意了,不是還沒初始化的 Bean ,是正在初始化的。想一下,有沒有什么問題?
// TODO 是不是為了避免循環(huán)依賴???畢竟這里是配置類,如果配置類依賴了馬上要代理的單例(或者其他)類,解決循環(huán)依賴肯定是要失敗的吧
// 所以,這里快刀斬亂麻,直接把這種危險依賴過濾掉了。雞賊啊
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
} else {
try {
// 都是創(chuàng)建好的或者還沒開始創(chuàng)建的,把他們實例化然后收集起來
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)) {
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;
}
整體思路比較簡單,就是找出了BeanFactory中配置的所有的Advisor,然后實例化返回。
接下來看第二步:根據(jù)Bean篩選出可用的增強器
// 檢索增強器列表,找出所有可以用于 bean 代理的增強器
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 使用 ThreadLocal 保存此線程正在生成代理的目標 beanId ,應(yīng)該是為了監(jiān)控及防止死循環(huán)吧
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 老套路,處理完信息記錄、條件驗證之后,將要干的活委托給專門干這個活的人
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
} finally {
// 清除之前存儲的 beanId
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
我們繼續(xù)深入看詳細的實現(xiàn)思路:
// 從入?yún)⒌脑鰪娖髁斜碇泻Y出入?yún)⒌腸lass可用的
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) { // 沒得選,就返回空
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
//IntroductionAdvisor 判斷
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 非 IntroductionAdvisor 判斷是否可用
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
這里分了兩種判斷,很簡單,因為Advisor分兩種:
-
IntroductionAdvisor只判斷到類級別 -
PointcutAdvisor判斷到方法級別
有興趣可以深入去看,不過根據(jù)猜測,我們用到的應(yīng)該都是第二種。
到這里,我們找出了所有可用的增強器。
createProxy
上面我們篩選出了合適的增強器,現(xiàn)在開始根據(jù)增強器構(gòu)建動態(tài)代理。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//這里應(yīng)該是把代理處理之前的類進行保存
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory(); // 創(chuàng)建 ProxyFactory ,后面將用此對象通過傳進去的信息決定 JDK/CGLIB 的選擇
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) { // 只有在沒有設(shè)置必須使用 CGLib 時才根據(jù)什么 BD字段、BD指定Class的接口進行判斷
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 一個鉤子,方便定制
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader()); // 代理的創(chuàng)建和獲取
}
我們在這個函數(shù)主要根據(jù)Bean實例的情況和配置進行判斷,并將判斷的結(jié)果設(shè)置到proxyFactory中,具體的創(chuàng)建操作委托給了proxyFactory。
其實最關(guān)鍵的,這里做了一個判斷,設(shè)置了兩個屬性:
- 判斷了創(chuàng)建代理的方式:CGLib還是JDK。
- 設(shè)置了代理的目標實例,設(shè)置了動態(tài)代理的切面邏輯——增強器列表。
如果強制使用CGLib就直接使用,否則根據(jù)實例實現(xiàn)的接口判斷能否使用JDK:
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
// 得到此類實現(xiàn)的所有接口
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false;
// 篩選一下接口,看有沒有可以用來代理的,如果有就可以考慮 JDK 動態(tài)代理了。如果沒有只能走 CGLIB
for (Class<?> ifc : targetInterfaces) {
// 1. 不能是那些 Spring 容器回調(diào)的接口
// 2. 不能是那些本地鏈接庫的
// 3. 接口不能是空的
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
ifc.getMethods().length > 0) {
hasReasonableProxyInterface = true;
break;
}
}
// 如果有符合條件的,就都存起來
// TODO 這里沒有專門篩選那些,看看后面根據(jù)存的接口使用時有沒有過濾
// TODO 感覺這里做的不是特別好
if (hasReasonableProxyInterface) {
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
} else {
// 沒有符合條件的接口,直接設(shè)置用 CGLIB 生成代理
proxyFactory.setProxyTargetClass(true);
}
}
這里整體的判斷思路還是比較清晰的。
至此,我們就把配置都設(shè)置到proxyFactory了,接下來我們看一下proxyFactory創(chuàng)建動態(tài)代理的策略。
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
這里直接委托給了AopProxyFactory,我們繼續(xù)深入:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果有特殊配置或者類的情況要求用 CGLIB
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 配置不合理,按照實際情況決定用 JDK 動態(tài)代理
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config); // 否則根據(jù)配置用 CGLIB 動態(tài)代理
} else { // 默認用 JDK 動態(tài)代理
return new JdkDynamicAopProxy(config);
}
}
思路很順暢,至此我們根據(jù)配置和具體的信息得到了一個JdkDynamicAopProxy或者一個ObjenesisCglibAopProxy。
他們的工作原理下文會進行介紹。
擴展
Bean 后處理器相關(guān)介紹
BeanPostProcessor
提供了兩個針對Bean的處理鉤子,在調(diào)用初始化鉤子前后進行調(diào)用。
postProcessBeforeInitialization:
調(diào)用場景:Bean填充屬性完成,在
initializeBean()方法中先調(diào)用這個,再調(diào)用初始化的函數(shù)返回結(jié)果:返回加工結(jié)果,如果返回null,后面的
postProcessBeforeInitialization就不再調(diào)用了【同時,此后處理器返回的也不再被使用】
postProcessAfterInitialization:后處理器方法,可以在這里進行代理創(chuàng)建
調(diào)用場景:在
initializeBean()方法中調(diào)用初始化的函數(shù)完成返回結(jié)果:返回加工結(jié)果,如果返回null,后面的
postProcessAfterInitialization就不再調(diào)用了【同時,此后處理器返回的也不再被使用】
InstantiationAwareBeanPostProcessor
繼承自上面的接口,新增兩個后處理鉤子用于在創(chuàng)建實例前后調(diào)用。
postProcessBeforeInstantiation:后處理器方法, 可以在這里直接創(chuàng)建出實例并完成代理創(chuàng)建,這里會阻塞后面的幾乎所有操作【創(chuàng)建實例/依賴注入/初始化】(阻塞我們介紹的那一大串的正常創(chuàng)建Bean的邏輯)
調(diào)用場景:在
createBean()方法中調(diào)用,沒有返回結(jié)果才委托給doCreateBean()返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果不是null,后面的流程被全部繞過,直接調(diào)用
postProcessAfterInitialization,然后返回 Bean 實例
postProcessAfterInstantiation:
調(diào)用場景:走正常的創(chuàng)建邏輯,在創(chuàng)建完實例之后、填值之前調(diào)用
返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果是false,不再繼續(xù)調(diào)用,且不再繼續(xù)調(diào)用填值操作
postProcessPropertyValues: 處理的主題不是 Bean 實例
調(diào)用場景:調(diào)用完上面的后處理器,找到合適的屬性值之后調(diào)用這個方法對值進行處理
返回結(jié)果:返回加工結(jié)果,如果返回結(jié)果是null,不再使用此屬性值進行屬性填充
SmartInstantiationAwareBeanPostProcessor
繼承自上買呢的接口,增加了用來預(yù)測創(chuàng)建 bean 的返回實例類型的方法。
predictBeanType:預(yù)測 Bean 的Class,感覺不是很重要的地方
determineCandidateConstructors:決定使用 bean 的構(gòu)造函數(shù),不再深入
getEarlyBeanReference:獲得 bean 的提前引用,用來解決循環(huán)引用,可以在這里進行代理創(chuàng)建。
調(diào)用場景:創(chuàng)建實例完成,是單例,需要先暴露實例以解決循環(huán)依賴再進行填值。調(diào)用此后處理器處理之后再暴露。
返回結(jié)果:返回加工結(jié)果,默認返回原對象。