前言
讓我們繼續(xù)講解Spring的Bean實(shí)例化過程。在上一節(jié)中,我們已經(jīng)講解了Spring是如何將Bean定義加入到IoC容器中,并使用合并的Bean定義來包裝原始的Bean定義。接下來,我們將繼續(xù)講解Spring的 getBean()
方法,特別是針對 FactoryBean
的解析。
在 getBean()
方法中,Spring還支持對 FactoryBean
進(jìn)行特殊處理。FactoryBean
是一個(gè)能夠生成Bean實(shí)例的工廠Bean,其定義了 getObject()
方法,返回的是一個(gè)由工廠Bean管理的對象實(shí)例。在使用 getBean()
方法獲取 FactoryBean
類型的Bean時(shí),Spring會(huì)首先獲取 FactoryBean
的實(shí)例,然后調(diào)用其 getObject()
方法來獲取由工廠Bean創(chuàng)建的實(shí)際Bean實(shí)例。
因此,在使用 getBean()
方法獲取Bean實(shí)例時(shí),我們需要注意是否需要對 FactoryBean
進(jìn)行特殊處理。如果需要獲取 FactoryBean
的實(shí)例而不是它所管理的對象實(shí)例,可以在Bean名稱前加上 &
符號來進(jìn)行標(biāo)識。例如:&myFactoryBean
表示獲取 myFactoryBean
的實(shí)例。但是博主看到第一篇源碼寫的篇幅確實(shí)有些長,可能對于大家伙的碎片化時(shí)間掌握的不是很充分,所以以后我會(huì)盡力控制篇幅長度,既保證邏輯的連續(xù)性也保證盡快可以看完,那么接下來開始進(jìn)入正題getbean方法之FactoryBean解析。
FactoryBean
所有符合過濾條件的Bean在Spring解析后都會(huì)被轉(zhuǎn)化為合并后的Bean定義。盡管Spring提供了 getBean()
方法用于獲取Bean實(shí)例,但實(shí)際上它底層仍然使用 createBean()
方法來創(chuàng)建Bean實(shí)例。在創(chuàng)建Bean實(shí)例之前,Spring先對當(dāng)前Bean定義進(jìn)行判斷,以確定其是否為 FactoryBean
類型:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// 獲取合并后的BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 獲取FactoryBean對象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
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) {
// 創(chuàng)建真正的Bean對象(getObject()返回的對象)
getBean(beanName);
}
}
}
else {
// 創(chuàng)建Bean對象
getBean(beanName);
}
}
}
// 所有的非懶加載單例Bean都創(chuàng)建完了后
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
他的源碼邏輯大致如下:
- Spring會(huì)根據(jù)
beanName
去bean
定義Map
中獲取當(dāng)前合并的Bean
定義。 - Spring會(huì)對當(dāng)前
Bean
定義進(jìn)行判斷,包括判斷當(dāng)前Bean
是否為抽象的、是否為單例、是否懶加載,以及是否為FactoryBean
。如果是FactoryBean
,則會(huì)走FactoryBean
的創(chuàng)建邏輯,否則會(huì)走單例Bean
的創(chuàng)建邏輯。 - 當(dāng)所有單例非懶加載的
Bean
創(chuàng)建完成后,Spring會(huì)遍歷所有單例Bean
,判斷其是否為SmartInitializingSingleton
類型。如果是,則會(huì)自動(dòng)調(diào)用afterSingletonsInstantiated
方法。
isFactoryBean
由于創(chuàng)建 Bean
的邏輯比較復(fù)雜,其中包含了許多細(xì)節(jié),因此,在這里我們特別提到了一個(gè)方法 isFactoryBean()
。之所以要提到這個(gè)方法,是因?yàn)镾pring支持使用 FactoryBean
來創(chuàng)建復(fù)雜對象。下面是該方法的主要源碼:
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
大致邏輯如下:
-
transformedBeanName
的作用是不管傳入的參數(shù)是&×××
還是×××
,都返回×××
。這是因?yàn)镾pring標(biāo)記FactoryBean
時(shí)使用&×××
作為FactoryBean
的beanName
。 -
getSingleton
方法從單例池中獲取Bean
實(shí)例,如果該實(shí)例是FactoryBean
,則直接返回該實(shí)例。 - 如果
BeanFactory
中的Bean
定義Map
中不包含該beanName
的Bean
定義,并且當(dāng)前BeanFactory
的父BeanFactory
實(shí)現(xiàn)了ConfigurableBeanFactory
接口,那么就需要查看當(dāng)前父BeanFactory
中是否有該實(shí)例,并且判斷該實(shí)例是否為FactoryBean
。舉個(gè)例子來說:
// 創(chuàng)建一個(gè)父Spring容器
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.register(AppConfig.class);
parent.refresh();
// 創(chuàng)建一個(gè)Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.setParent(parent);
applicationContext.register(AppConfig1.class);
applicationContext.refresh();
UserService bean = applicationContext.getBean(UserService.class);
bean.test();
- 如果并沒有實(shí)例化出來的bean,那么對bean定義進(jìn)行判斷。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Boolean result = mbd.isFactoryBean;
if (result == null) {
// 根據(jù)BeanDefinition推測Bean類型(獲取BeanDefinition的beanClass屬性)
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
// 判斷是不是實(shí)現(xiàn)了FactoryBean接口
result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
mbd.isFactoryBean = result;
}
return result;
}
注釋也基本寫好了,基本上就是根據(jù)BeanDefinition推測Bean類型(獲取BeanDefinition的beanClass屬性),再根據(jù)bean類型判斷是不是實(shí)現(xiàn)了FactoryBean接口,然后返回判斷結(jié)果。
SmartFactoryBean
在 getBean
方法中,我們可以獲取 FactoryBean
的實(shí)例并返回。接下來的步驟是判斷當(dāng)前的 FactoryBean
是否實(shí)現(xiàn)了 SmartFactoryBean
接口。需要注意的是,SmartFactoryBean
是 FactoryBean
接口的一個(gè)子接口。雖然我們在實(shí)現(xiàn) FactoryBean
接口時(shí)不必實(shí)現(xiàn) SmartFactoryBean
接口,但是如果實(shí)現(xiàn)了 SmartFactoryBean
接口,那么在創(chuàng)建 FactoryBean
時(shí)就會(huì)調(diào)用 getObject
方法返回實(shí)例。正常情況下,只有當(dāng)容器啟動(dòng)完成后才會(huì)調(diào)用 getObject
方法。如果我們想在初始化時(shí)就調(diào)用,可以這樣實(shí)現(xiàn):文章來源:http://www.zghlxwxcb.cn/news/detail-431046.html
@Component
public class UserFactory implements SmartFactoryBean {
@Override
public Object getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}
結(jié)語
FactoryBean 和 BeanFactory 是兩個(gè)不同的概念。前者是一個(gè)接口,我們可以在實(shí)現(xiàn)該接口時(shí)通過調(diào)用 getObject
方法來返回實(shí)例,同時(shí) FactoryBean
本身也是一個(gè)實(shí)例。后者是 Spring 容器的工廠,通過其中的 bean
定義 Map
一個(gè)一個(gè)地實(shí)例化我們通過注解等方式注入進(jìn)去的 bean
工廠。在判斷 FactoryBean
時(shí),如果當(dāng)前 BeanFactory
中沒有對應(yīng)的 bean
定義,那么就會(huì)去父容器中尋找相應(yīng)的 bean
定義并進(jìn)行判斷。如果我們的類實(shí)現(xiàn)了 SmartFactoryBean
接口,那么它將會(huì)在 Spring 容器啟動(dòng)時(shí)就會(huì)調(diào)用 getObject
方法創(chuàng)建實(shí)例。接下來,我們將分幾個(gè)小節(jié)來講解 getBean
方法是如何實(shí)例化 bean
的,因?yàn)槠^長會(huì)影響讀者的注意力和學(xué)習(xí)效果。文章來源地址http://www.zghlxwxcb.cn/news/detail-431046.html
到了這里,關(guān)于Spring源碼:Bean的生命周期(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!