天天看點

Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 & 使用場景

文章目錄

  • BeanFactory VS FactoryBean
  • FactoryBean VS 普通Bean
  • 示範
  • 源碼
  • 使用場景
Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 & 使用場景

BeanFactory VS FactoryBean

首先明确一下,這兩個東西是完全不同的兩個東西 ,不要混淆。

BeanFactory 是Spring Framework的 頂級核心接口 , 沒有這個接口,就沒有Bean的産生。

FactoryBean也是一個接口,是一個特殊的Bean , 實作了FactoryBean 接口的Bean,原來的Bean将會被隐藏,而是由FactoryBean 的getObjecct方法傳回最終的Bean 。 簡單工廠模式 。

如果需要擷取FactoryBean執行個體本身,需要 & 。

可以把FactoryBean了解為4S店,改裝你原來的Bean。

FactoryBean VS 普通Bean

FactoryBean和普通Bean不同,其傳回的對象不是指定類的一個執行個體,而是該FactoryBean的getObject方法所傳回的對象。建立出來的對象是否屬于單例由isSingleton中的傳回決定。

Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 & 使用場景
Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 & 使用場景

【Bean1】

package com.artisan.factoryBean;


import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class Bean1 {

	@PostConstruct
	public void init(){
		System.out.println("bean1 create ");
	}
}

           

【SpecialBeanFB 實作了 FactoryBean接口 】 用于裝飾Bean

package com.artisan.factoryBean;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class SpecialBeanFB implements FactoryBean {


	@PostConstruct
	public void init(){
		System.out.println("SpecialBean as Factory Bean create ");
	}

	@Override
	public Object getObject()  {
		return new Bean2();
	}

	@Override
	public Class<?> getObjectType() {
		return Bean2.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
}

           

如果SpecialBeanFB這個FactoryBean上的Component注解 增加了 name ,例如

@Component("aaa")

其實是個getObject對象起的名字,而不是本身這個FactoryBean執行個體

當我們需要擷取FactoryBean執行個體本身而不是它所産生的bean,要使用&符号

比如這裡的 id為”specialBeanFB”的FactoryBean :

  • 調用getBean(“specialBeanFB”)将傳回FactoryBean産生的bean
  • 調用getBean("&specialBeanFB")将傳回FactoryBean它本身的執行個體

【配置類】

package com.artisan.factoryBean;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.artisan.factoryBean")
public class FBConfig {


}

           

【測試類】

package com.artisan.factoryBean;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class FactoryBeanTest {

	public static void main(String[] args) throws Exception {
		// 執行個體化Spring Bean 容器
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(FBConfig.class);

		// 從bean容器中讀取普通的bean
		System.out.println(ac.getBean(Bean1.class));
		System.out.println(ac.getBean("bean1"));
		System.out.println("===========");

		// 從bean容器中讀取FactoryBean接口修飾的Bean
		System.out.println(ac.getBean(SpecialBeanFB.class).getObject().getClass().getName());
		System.out.println(ac.getBean("specialBeanFB"));
		System.out.println("===========");

		// 通過 &  擷取 FactoryBean本身的bean對象
		System.out.println(ac.getBean("&specialBeanFB"));
		System.out.println("===========");

		// 如果SpecialBeanFB這個FactoryBean上的Component注解 增加了 name ,例如@Component("aaa")
		// 其實是個getObject對象起的名字,而不是本身這個FactoryBean執行個體
//		System.out.println(ac.getBean("aaa"));
//		System.out.println(ac.getBean("&aaa"));
		
	}
}

           

【測試結果】

Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 &amp; 使用場景
Spring5源碼 - 08 BeanFactory和FactoryBean 源碼解析 &amp; 使用場景

在執行個體化Bean的方法中

AbstractApplicationContext # refresh() 
    ---------- finishBeanFactoryInitialization(beanFactory) 
		   ----- DefaultListableBeanFactory#preInstantiateSingletons
           

在Spring容器啟動階段,會調用到refresh()方法,在refresh()中調用了finishBeanFactoryInitialization()方法,最終會調用到beanFactory.preInstantiateSingletons()方法

public void preInstantiateSingletons() throws BeansException {
	// 從容器中擷取到所有的beanName
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	for (String beanName : beanNames) {
		// 合并Bean   ScannedGenericBeanDefinition AnnotatedGenericBeanDefinition 類型的Bean 等等 都要合并為 RootBeanDefinition 比較複雜,知道即可
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 建立Bean的條件校驗
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 在此處會根據beanName判斷bean是不是一個FactoryBean,實作了FactoryBean接口的bean,會傳回true 
			if (isFactoryBean(beanName)) {
				// 然後通過getBean()方法去擷取或者建立單例對象
				// 注意:在此處為beanName拼接了一個字首:FACTORY_BEAN_PREFIX  是一個常量字元串,即:&
				// 是以在此時容器啟動階段,對于specialBeanFB,應該是:getBean("&specialBeanFB")
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				// 下面這一段邏輯,是判斷是否需要在容器啟動階段,就去執行個體化getObject()傳回的對象,即是否調用FactoryBean的getObject()方法
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
		}
	}
}
 
           
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
	// ...省略其他代碼
	
	public SqlSessionFactory getObject() throws Exception {
	if (this.sqlSessionFactory == null) {
	  afterPropertiesSet();
	}

	return this.sqlSessionFactory;
	}
}

           
public void afterPropertiesSet() throws Exception {
    // buildSqlSessionFactory()方法會根據mybatis的配置進行初始化。
	this.sqlSessionFactory = buildSqlSessionFactory();
}