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="https://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="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyUser {
}
xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myFactoryBean" class="com.redwinter.selffactorybean.MyFactoryBean"/>
</beans>
測試類:
/**
* @author <a href="https://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
的建立過程非常複雜,下一篇繼續。