Spring版本:5.1.3.RELEASE
BeanFactory
接口:
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
是簡單工廠模式的應用,根據傳入的beanName執行個體化相應的執行個體。
JavaDoc翻譯(使用Google翻譯并加以潤色,如有歧義歡迎指出):
用于通路Spring bean容器的根接口。 這是bean容器的基本用戶端視圖; 其他接口(如ListableBeanFactory和org.springframework.beans.factory.config.ConfigurableBeanFactory)可用于特定目的。
該接口被一些持有bean定義的對象實作,每個bean定義由一個字元串名稱唯一辨別。
根據bean定義,工廠将傳回包含對象的獨立執行個體(Prototype設計模式)或單個共享執行個體(Singleton設計模式的進階替代,其中執行個體是工廠範圍中的單例)。
将傳回哪種類型的執行個體取決于bean工廠配置:API是相同的。
從Spring 2.0開始,根據具體的應用程式上下文(例如Web環境中的“request”和“session”範圍),可以使用更多的scope(範圍)。
這種方法的重點是BeanFactory是應用元件的注冊中心和集中的配置中心(例如,不再需要單個對象去讀取屬性檔案)。
有關此方法的優點的讨論,請參見"Expert One-on-One J2EE Design and Development"的第4章和第11章。
請注意,依靠依賴注入(“push”配置)通過setter或構造函數來配置應用對象通常更好,而不是像BeanFactory查找一樣的使用“pull”配置的任意方式。Spring的依賴注入功能是使用這個BeanFactory接口及其子接口實作的。
通常,BeanFactory将加載存儲在配置源(例如XML文檔)中的bean定義,并使用org.springframework.beans包來配置bean。盡管如此,一種簡單地實作是直接在Java代碼中傳回Java對象。如何存儲定義沒有限制:LDAP,RDBMS,XML,屬性檔案等。鼓勵實作支援bean之間的引用(依賴注入)。
與ListableBeanFactory中的方法相反,如果這是HierarchicalBeanFactory,則此接口中的所有操作也将檢查父工廠。如果在此工廠執行個體中找不到bean,則會詢問直接父工廠(從父類bean工廠中擷取)。此工廠執行個體中的Bean應該在任何父工廠中覆寫同名的Bean。
Bean工廠實作應盡可能支援标準bean生命周期接口。 完整的初始化方法及其标準順序是:
- BeanNameAware 接口的 setBeanName 方法
- BeanClassLoaderAware 接口的 setBeanClassLoader 方法
- BeanFactoryAware 接口的 setBeanFactory 方法
- EnvironmentAware 接口的 setEnvironment 方法
- EmbeddedValueResolverAware 接口的 setEmbeddedValueResolver 方法
- ResourceLoaderAware 接口的 setResourceLoader 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
- ApplicationEventPublisherAware 接口的 setApplicationEventPublisher 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
- MessageSourceAware 接口的 setMessageSource 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
- ApplicationContextAware 接口的 setApplicationContext 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
- ServletContextAware 接口的 setServletContext 方法 (僅适用于在應用程式上下文(Application Context)中運作時)
- 所有實作了BeanPostProcessor接口的類的 postProcessBeforeInitialization 方法
- InitializingBean 接口的 afterPropertiesSet 方法
- 自定義的init方法
- 所有實作了BeanPostProcessor接口的類的 postProcessAfterInitialization 方法
關閉Bean工廠時,應用以下生命周期方法:
- 所有實作了DestructionAwareBeanPostProcessor接口的類的 postProcessBeforeDestruction 方法
- DisposableBean 接口的 destroy 方法
- 自定義的destroy 方法
Spring Bean生命周期圖:

Spring 4.3.17.RELEASE 源碼的JavaDoc文檔寫的也是以上流程。跟其它網上的文章寫的流程有出入,應該以官方文檔為準。
FactoryBean
接口:
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
是工廠方法模式的應用,由子類實作相應的執行個體。
JavaDoc翻譯(使用Google翻譯并加以潤色,如有歧義歡迎指出):
接口被BeanFactory中使用的對象所實作,這些對象本身就是單個對象的工廠。如果bean實作了這個接口,它将被用作暴露此對象的工廠,而不是直接将自己作為bean執行個體給暴露出來。
注意:實作此接口的bean不能用作普通bean。
FactoryBean是被定義成bean的形式,但是bean對象的引用(getObject()方法獲得)始終是由它建立的。
FactoryBeans可以支援單例和原型,可以根據需要懶惰地建立對象,也可以在啟動時急切地建立對象。
SmartFactoryBean接口允許公開更細粒度的行為中繼資料。
該接口在架構内部大量使用,例如用于AOP的 org.springframework.aop.framework.ProxyFactoryBean類 或 org.springframework.jndi.JndiObjectFactoryBean類。
它也可以用于定制元件;但是,這僅适用于基礎架構代碼。
FactoryBean是一個programatic contract (程式設計合約)。實作不應該依賴annotation-driven (注解驅動)的注入或其他反射設施。
getObjectType()和getObject()方法的調用可能在引導過程的早期發生,甚至在所有的(post-processor)後置處理器設定之前。
如果您需要通路其他bean,請實作 BeanFactoryAware 并以程式設計方式擷取它們。
最後,FactoryBean對象參與包含BeanFactory的bean建立的同步。
除了FactoryBean本身(或類似)中的延遲初始化之外,通常不需要内部同步。
下面從源碼層面深入分析二者差別:
檢視 BeanFactory接口的抽象類 AbstractBeanFactory的getObjectForBeanInstance方法的實作:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// bean的name如果以&開頭,則是FactoryBean執行個體
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 驗證是否是FactoryBean對象,不是則抛出異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 執行到此處,已經得到了bean執行個體,如果是普通的bean,或者是FacoryBean執行個體,直接傳回.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 從FactoryBeanObjectCache中擷取由FactoryBean建立的bean對象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// beanInstance強轉為FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 如果是單例,則緩存從FactoryBean擷取的對象
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 最終調用FactoryBean執行個體的getObject方法擷取bean執行個體
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
在getObjectFromFactoryBean方法實作中會調用doGetObjectFromFactoryBean方法:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
// 調用FactoryBean的getObject方法來傳回執行個體
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
......
}
else {
// 調用FactoryBean的getObject方法來傳回執行個體
object = factory.getObject();
}
}
......
return object;
}
實作FactoryBean的類,在初始化放入容器後,通過BeanFactory的getBean方法調用時,會調用FactoryBean的getObject方法傳回對應的bean執行個體對象,而不是像普通的bean一樣直接傳回bean執行個體.
BeanFactory的常量&的作用是在擷取bean的時候直接傳回FactoryBean的bean執行個體,而不是調用的getObject方法傳回對應的bean執行個體.
以上,如有問題歡迎提出!
參考: https://blog.csdn.net/silk_bar/article/details/60967064