透過源碼看本質——Spring AOP 在IoC之後,在DI之前

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()這個方法,最後調用AbstractAutoProxyCreatorwrapIfNecessary()方法產生,代碼如下:

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生成自己的代理對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章