在上一篇文章中,我一步步分析了使用 BeanFactory 獲取並創建 Bean 的過程,並且解釋了 Spring 是如何解決循環依賴的?
- 上一篇博客:Spring是如何解決循環依賴的?
類繼承結構
- DefaultSingletonBeanRegistry 負責單例的注冊
- AbstractAutowireCapableBeanFactory 自動裝配工廠
創建Bean核心過程簡化
其中,橙色為 protected 方法,綠色為 public 方法
- getBean 獲取並創建 Bean
- doGetBean 具體的獲取方法
- doCreateBean 具體的創建 Bean 的方法
- populateBean 填充屬性
- 填充屬性時,有可能需要獲取並創建新的 Bean,再次回到第 1 步
接口 BeanFactory 中的 getBean 方法有 5 個:
其中 2 個以對象類型為參數的 getBean 方法是由 DefaultListableBeanFactory 實現的。
// 返回與給定對象類型唯一匹配的bean實例(如果有)
public <T> T getBean(Class<T> requiredType) throws BeansException { // ...(省略) }
// 返回指定bean的實例,該實例可以是共享的,也可以是獨立的。
// 允許指定顯式構造函數參數/工廠方法參數,並覆蓋bean定義中指定的默認參數(如果有)
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException { // ...(省略) }
剩下 3 個由 AbstractBeanFactory 實現,並且都調用了 doGetBean 方法
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
Spring 創建俯瞰圖
這個是我自己畫的一張Spring 創建單例 Bean 的流程圖,看不懂先別着急,讓我接下來細細分說。
getSingleton
獲取單例的兩個方法都是在 DefaultSingletonBeanRegistry 中實現的。
getSingleton(beanName, singletonFactory)
首先介紹的是參數為 ObjectFactory 的getSingle方法:
/**
* 返回以給定名稱注冊的(原始)單例對象,
* 如果尚未注冊,則創建並注冊一個新的。
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { // ...(省略) }
該方法內的重要方法如圖所示:
beforeSingletonCreation(String beanName) 和 afterSingletonCreation(String beanName) 一個標識創建開始,一個標識創建結束,與之相關的還有一個方法
/**
* 返回指定的單例bean當前是否正在創建中
*/
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
其中,singletonsCurrentlyInCreation 是保存正在創建中的單例bean的集合。
我們知道,調用該 getSingleton 方法是在 doGetBean 中,且其匿名內部類調用的是 createBean 方法,該方法被 AbstractAutowireCapableBeanFactory 覆寫。源碼如下
// AbstractBeanFactory.class
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// ... 省略
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ... 省略
}
// 需要 AbstractBeanFactory 的子類覆寫,最終由 AbstractAutowireCapableBeanFactory 實現
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException;
addSingleton(String beanName, Object singletonObject) 方法將給定的單例對象添加到該工廠的單例緩存中。
即添加到singletonObjects 單例池中。
getSingleton(beanName, allowEarlyReference)
/**
* 返回以給定名稱注冊的(原始)單例對象。
* 檢查已經實例化的單例,並且還允許對當前創建的單例的早期引用(解決循環引用)。
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
這個方法涉及到 DefaultSingletonBeanRegistry 的三個集合:
- singletonObjects 是單例的緩存,可以避免重復創建單例
- earlySingletonObjects 是未完成單例的緩存,用來解決循環依賴
- singletonFactories 是單例工廠集,也是用來解決循環依賴的,當方法參數 allowEarlyReference 為 true 時才會取出對應的單例工廠,執行創建,並且將單例的早期引用放入未完成單例集中。
如圖所示,getSingleton(String beanName) 方法是目前唯一允許創建單例的早期引用的方法。
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
doCreateBean
接下來,我們關注到實際負責創建 Bean 的方法 doCreateBean。createBean 是由 AbstractAutowireCapableBeanFactory 覆寫的,doCreateBean 也是該類的方法
- createInstance 實例化Bean
- addSingletonFactory 是在發生循環依賴的情況下,添加 ObjectFactory 到單例工廠集singletonFactories中
- populateBean 填充屬性
- initializeBean 初始化Bean
初始化Bean
初始化 Bean 又分為3個步驟:
- applyBeanPostProcessorsBeforeInitialization 在執行初始化方法之前,進行前置操作
- invokeInitMethods 執行初始化方法
最常見的就是實現 InitializingBean 接口:
public interface InitializingBean {
/**
* 此方法允許Bean實例在設置所有Bean屬性后執行其整體配置的驗證和最終初始化。
*/
void afterPropertiesSet() throws Exception;
}
- applyBeanPostProcessorsAfterInitialization 在執行初始化方法之后,執行后置操作
以下是一個簡單的代碼示例:
// 實現初始化方法的類
public class MessageList implements InitializingBean {
private List<String> messages = new ArrayList<>();
public MessageList() {
messages.add("createInstance");
}
public void addMessage(String msg) {
messages.add(msg);
}
@Override
public void afterPropertiesSet() throws Exception {
messages.add("afterPropertiesSet");
}
public void printAllMessages() {
for (String message : messages) {
System.out.println(message);
}
}
}
測試類:
public class BeanFactoryTest {
@Test
public void messageListTest() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MessageList) {
((MessageList) bean).addMessage("postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MessageList) {
((MessageList) bean).addMessage("postProcessAfterInitialization");
}
return bean;
}
});
RootBeanDefinition def = new RootBeanDefinition(MessageList.class);
factory.registerBeanDefinition("messageList", def);
MessageList bean = factory.getBean(MessageList.class);
bean.printAllMessages();
}
}
輸出結果:
循環依賴的后置處理
假設 AService 和 BService 構成循環依賴
public class AService {
private BService bService;
public BService getBService() {
return bService;
}
public void setBService(BService bService) {
this.bService = bService;
}
}
public class BService {
private AService aService;
public AService getAService() {
return aService;
}
public void setAService(AService aService) {
this.aService = aService;
}
}
然后我們寫出測試類
public class ABServiceBeanFactoryTest {
@Test
public void test() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.addBeanPostProcessor(new SmartInstantiationAwareBeanPostProcessor() {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (bean instanceof AService) {
return new AService$Proxy((AService) bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
});
{
RootBeanDefinition definition = new RootBeanDefinition(AService.class);
definition.setPropertyValues(new MutablePropertyValues().add("bService", new RuntimeBeanReference(BService.class)));
factory.registerBeanDefinition("aService", definition);
}
{
RootBeanDefinition definition = new RootBeanDefinition(BService.class);
definition.setPropertyValues(new MutablePropertyValues().add("aService", new RuntimeBeanReference(AService.class)));
factory.registerBeanDefinition("bService", definition);
}
AService bean = factory.getBean(AService.class);
Assert.assertEquals(bean, bean.getBService().getAService());
}
public static class AService$Proxy extends AService {
private AService aService;
public AService$Proxy(AService aService) {
this.aService = aService;
}
@Override
public BService getBService() {
return aService.getBService();
}
}
}
BeanPostProcessor 接口對循環依賴不起作用
第一個值得注意的點,對於循環依賴 aService 而言,只有 SmartInstantiationAwareBeanPostProcessor 才能夠后置處理 AService 的未完成實例,原因在 getEarlyBeanReference 方法中
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 只有 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 才能后置處理未完成的實例
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
為什么 postProcessAfterInitialization 對循環依賴對象不起作用?
第二點,如果增加了 postProcessBeforeInitialization(Object bean, String beanName) 和 postProcessAfterInitialization(Object bean, String beanName) 后置處理方法,bean對象都是 AService 而不是 AService$Proxy ,但是最后 getBean 返回的結果是 AService$Proxy。
如圖所示,postProcessAfterInitialization 傳入的 Bean 對象是 AService。
如圖所示,最終返回的是 AService$Proxy 對象,這是怎么做到的?
答案就在 AbstractAutowireCapableBeanFactory#doCreateBean 方法中,請看下圖
結論:在發生循環依賴時,無論你在 postProcessBeforeInitialization 和 postProcessAfterInitialization 做何種后置處理,最終暴露給 BService 對象使用的引用,以及最后 getBean 返回的都將是 getEarlyBeanReference 后置處理后的 AService 對象。