spring的IoC的流程可以分爲定位
、加載
、註冊
三個步驟,在IoC容器中註冊的是BeanDefinition,BeanDefinition就是解析出來的存儲bean對象的。
接着,進行DI操作,需要對BeanDefinition進行初始化,變成一個實例化的對象,最開始是調用的DefaultListableBeanFactory
類的getBean()
方法,此處不在詳細描述,可以參考我另外一篇文章的Spring IoC的流程圖,最終調用的是AbstractAutowireCapableBeanFactory
類中的doCreateBean()
方法裏的createBeanInstance()
方法,生成一個BeanWrapper對象,這個纔是我們真正使用的實例化bean對象。
spring IoC時序圖:
https://blog.csdn.net/qq_33996921/article/details/106115472
spring DI時序圖
https://blog.csdn.net/qq_33996921/article/details/106115589
源碼如下:
//AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
。。。。。。。。。省略。。。。。
if (instanceWrapper == null) {
//1、初始化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
。。。。。。。。。。。。。。。。。
// Initialize the bean instance.
Object exposedObject = bean;
try {
//2、DI依賴注入
populateBean(beanName, mbd, instanceWrapper);
//3、對exposedObject進行處理,生成代理類
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
doCreateBean()
這個方法其實包含三個非常重要的三個步驟:
1、createBeanInstance(),實例化bean,生成一個BeanWrapper對象;
2、populateBean():依賴注入;
3、initializeBean():對exposedObject進行處理,生成代理類;
此處並沒有直接將生成的instanceWrapper
對象直接暴露出來,而是將exposedObject
對象暴露出來,這個對外暴露的對象是經過代理生成後的對象,如果沒有代理的對象,那其實跟instanceWrapper
對象是同一個對象。
簡單看一下initializeBean()
這個方法:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
......省略代碼......
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
代理對象其實就是調用applyBeanPostProcessorsAfterInitialization()
這個方法,最後調用AbstractAutoProxyCreator
類wrapIfNecessary()
方法產生,代碼如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
。。。。。。。。省略。。。。。。。。
// Create proxy if we have advice.
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;
}
從上面可以看到代碼中有創建代理對象的createProxy()
方法了,具體的就不往下跟了。
言歸正傳,我們來說一下我們今天的主題,爲什麼說Spring的AOP是在IoC之後,再DI之前呢?
通過上面的源碼分析,
1)IoC階段先創建了容器,並將BeanDefinition
註冊到容器中;
2)初始化Bean,生成了BeanWrapper
,再對BeanWrapper
進行依賴注入;
3)在DI的過程中,如果發現set的屬性值是沒有初始化bean
的,就先對其進行初始化操作,然後繼續循環調用getBean()
方法,如果是此對象是代理對象就會將生成的exposedObject
對象依賴注入進去。
三級緩存的對象如下:
//DefaultSingletonBeanRegistry.java
//一級緩存:
/** 保存所有的singletonBean的實例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二級緩存:
/** 保存所有早期創建的Bean對象,這個Bean還沒有完成依賴注入 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三級緩存:
//存放需要解決循環依賴的bean信息(beanName,和一個回調工廠)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
此時如果發生循環依賴,會使用Spring的三級緩存解決循環依賴的問題。本文中不對循環依賴做過多詳細描述,後續有時間我會專門再寫一篇關於解決循環依賴的文章。
總結一下:
從整體思想上說,在A對象依賴注入(DI)時,需要注入對象B的話,如果容器中沒有B的對象,需要再調用B的getBean,B的populateBean()
,B的initializeBean()
,通過initializeBean()
生成了B的代理對象,然後將B的代理對象在注入到A中,這裏也說明了在DI之前要先生成要注入屬性的代理對象。這也就我們說的Aop要在DI之前,但如果是隻針對自己的單個對象來說,還是拿A對象爲例子,A在完成依賴注入後,再經過AOP生成自己的代理對象。