Spring 源碼(10)Spring Bean 的創建過程(1)
Spring Bean
的創建剛開始進行了一些準備工作,比如轉換服務的初始化,佔位符解析器的初始化,BeanDefinition
元數據的凍結等操作,都是為了在創建Bean的過程中保證Bean
的正確的創建,接下來開始進行對Bean
的創建進行解析。
Bean 的創建步驟
在Spring
源碼中對Bean
的創建遵循一個步驟就是:getBean
–> doGetBean
–> createBean
–> doCreateBean
,常規的Bean
的創建過程都是按照這個步驟執行,然後反射實例化,屬性填充,初始化,放到一級緩存中。那麼非常規的有可能就不遵循這個步驟,比如FactoryBean
,InstantiationAwareBeanPostProcessor
等。
上源碼:
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...
// 遍歷所有的beanName
for (String beanName : beanNames) {
// 獲取RootBeanDefinition 從緩存中,第一個放入緩存是在 AbstractApplicationContext#invokeBeanFactoryPostProcessors 中的getBeanNamesForType方法中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果不是抽象的,是單例的,是非懶加載的,則進行bean的創建,否則直接跳過
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 是否是FactoryBean
if (isFactoryBean(beanName)) {
// 獲取bean實例
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 判斷獲取的Bean是否是FactoryBean
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 是否是飢餓初始化,默認是false
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());
}
// 如果是飢餓初始化,則進行bean的創建
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 獲取bean
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// 觸發 所有Bean初始化後的回調
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
// 獲取單例對象,如果是SmartInitializingSingleton 則調用afterSingletonsInstantiated
// 在監聽器中使用@EventListener註解標記的方法就是在這個方法中進行監聽器的添加的,會創建一個監聽器的適配器
// 調用類為 EventListenerMethodProcessor
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 權限檢查
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
通過源碼可以知道,Spring
前期在進行XML
進行loadBeanDefinitions
加載或者BeanFactoryPostProcessor
子類BeanDefinitionRegistryPostProcessor
的實現類ConfigurationClassPostProcessor
註解解析 出來的BeanDefinition
放入兩個集合BeanDefinitionMap
和BeanDefinitionNames
,這裡遍歷的是BeanDefinitionNames
這個集合,存放的是beanName
。
首先是進行了BeanDefinition的合併處理,最終返回的全是RootBeanDefinition,進入源碼可以看到這裡是從緩存中獲取的,如果有則直接取出來,否則再去解析。
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 從緩存中獲取
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
那麼第一次進行調用時什麼地方呢?是在進行BeanFactoryPostProcessor
的執行和解析時調用的,在解析BeanFactoryPostProcessor
時調用了 getBeanNamesForType
方法,然後調用doGetBeanNamesForType
時進行了BeanDefinitionNames
集合的遍歷合併Bean
:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
// 遍歷所有的BeanDefinitionNames集合
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
// 從本地緩存中獲取合併的BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// 是否是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorat
// 省略代碼....
}
}
}
}
所以在執行preInstantiateSingletons
預實例化單例時獲取的RootBeanDefinition
基本是從緩存中獲取的。
接着是判斷如果是單例的並且不是抽象的,不是懶加載的,那麼就進行Bean
的創建,然後又判斷是否是FactoryBean
,如果是那麼就進行下一步邏輯。
FactoryBean 是什麼?
FactoryBean
是用來創建Bean
對象的,他是一個接口,方法:
getObject
獲取bean對象getObjectType
獲取bean的類型isSingleton
是否是單例的,默認是true
在創建對象時,你可以直接在getObject
方法中進行new
,或者反射,或者是其他都可以,非常的靈活。接下來使用FactoryBean
進行自定義的Bean
的創建。
定義一個FactoryBean
的實現類:
/**
* @author <a href="//www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyFactoryBean implements FactoryBean<MyUser> {
@Override
public MyUser getObject() throws Exception {
// 直接new一個對象
return new MyUser();
}
@Override
public Class<?> getObjectType() {
return MyUser.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
定義MyUser
/**
* @author <a href="//www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyUser {
}
xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="//www.springframework.org/schema/beans"
xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xmlns:context="//www.springframework.org/schema/context"
xsi:schemaLocation="//www.springframework.org/schema/beans //www.springframework.org/schema/beans/spring-beans.xsd //www.springframework.org/schema/context //www.springframework.org/schema/context/spring-context.xsd">
<bean id="myFactoryBean" class="com.redwinter.selffactorybean.MyFactoryBean"/>
</beans>
測試類:
/**
* @author <a href="//www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class FactoryBeanTest {
@Test
public void test(){
MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");
Object myFactoryBean = context.getBean("myFactoryBean");
System.out.println(myFactoryBean);
Object myFactoryBean2 = context.getBean("&myFactoryBean");
System.out.println(myFactoryBean2);
}
}
輸出:
com.redwinter.test.selffactorybean.MyUser@2d554825
com.redwinter.test.selffactorybean.MyFactoryBean@68837a77
這裡可以看到FactoryBean
創建Bean
的時候,xml
註冊的是一個FactoryBean
的實現,但是獲取出來又是具體的MyUser
對象,這裡Spring
使用了懶加載的機制,在Spring
對Bean
進行初始化時,實際上只將FactoryBean
的實現類註冊到了Spring
容器中,當我們需要使用的時候,才去判斷,如果是FactoryBean
類型的,那麼就去調用getObject
方法去創建對象。如果是第二次去獲取Bean
,那麼是從緩存中獲取的,如果是獲取&
前綴的Bean
,那就直接返回。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 判斷是否是&前綴標識
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 從緩存中獲取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// 判斷是否是合成的Bean,是否是應用程序本身設置的,比如某些aop 就是合成的Bean
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 執行getObject方法獲取Bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
BeanFactory 和FactoryBean 的區別?
根據前面的文章介紹,我們知道BeanFactory
是一個Bean
的創建工廠,比如AbstractApplicationContext
就是BeanFactory
的實現類,這個類就是用來創建Bean
的,創建出來的Bean
放在緩存中。而FactoryBean
就是Bean
實例,是由BeanFactory
創建的,並且FactoryBean
也是用來創建Bean
對象,使用getObject
方法進行創建,也是會放在緩存中供下次直接獲取,而且如果在使用時需要使用FactoryBean
的實例時需要以&
前綴才能獲取到,比如getBean("&myFactoryBean");
如果是獲取通過getObject
方法創建的對象時,就不需要添加&
前綴,比如getBean("myFactoryBean");
總結一下:
相同點:
- 都是用來創建對象的
- 都是創建出來之後放入緩存中供下次直接使用
不同點:
BeanFactory
是一個對象創建工廠,而FactoryBean
是一個Bean
實例BeanFactory
創建的對象一般來說都是使用反射調用構造函數創建的,而FactoryBean
創建對象是調用getObject
方法創建,並且創建方式不一定是通過反射,可以是直接new
對象或者其他方式FactoryBean
在獲取對象時,可以獲取到兩個對象,一個是存放在BeanFactory
創建的緩存中,通過&beanName
獲取的FactoryBean
的實現類對象,一個是調用getObject
創建的,通過beanName
獲取的具體對象。
Bean
的創建過程非常複雜,下一篇繼續。