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" />
</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的創建程序非常復雜,下一篇繼續,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/471757.html
標籤:Java
上一篇:Spring與Web環境集成
