在之前的文章內容中,簡單介紹了bean定義的載入過程,下面這篇的主要內容就是bean例項的建立過程。
bean例項的建立方式
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
context.getBean("beanDemo");
首先看到上面的程式碼,使用了getBean方法,那麼建立bean的入口是不是在getBean裡面呢?
通過之前的內容,可以知道,單例bean可以提前例項化,因為能夠提高使用時的效率。原型bean,即多例bean則是在getBean的時候進行例項化的。而且單例bean和原型bean的例項化過程是沒有區別的,都是通過getBean方法,在啟動時提前例項化也是使用的getBean方法。
bean例項建立以及配置的方式如下:
- 構造方法的方式
通過建構函式建立例項有兩種方式,一種是無參建構函式,一種是有參建構函式
下面是無參建構函式的配置方式:
public class ConstructorBean {
public ConstructorBean() {
System.out.println("無參建構函式......");
}
}
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean" />
下面是有參建構函式的配置方式:
public class ConstructorBean {
public ConstructorBean(String name, int age) {
System.out.println("帶參建構函式......");
System.out.println(name + "_" + age);
}
}
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean">
<constructor-arg index="0" value="翠花" />
<constructor-arg index="1" value="18" />
</bean>
輸出結果如下:
- 靜態工廠方法
public class InstantiateFactory {
public static String getStaticFactoryMethod() {
return "靜態工廠方法建立bean......";
}
}
<bean id="boyService" class="edu.demo.spring.instantiate.InstantiateFactory"
factory-method="getStaticFactoryMethod" >
<!--<property name="" ref=""></property>-->
</bean>
- 非靜態工廠方法
public class InstantiateFactory {
public String getMemberFactoryMethod(String name) {
return "非靜態工廠方法建立bean......";
}
}
<bean id="instantiateFactory" class="edu.demo.spring.instantiate.InstantiateFactory" />
<bean id="grilService" factory-bean="instantiateFactory"
factory-method="getMemberFactoryMethod" >
<!--<constructor-arg index="0" value="你好" />-->
</bean>
- 指定工廠方法
需要繼承FactoryBean介面:
public class BoyFactoryBean implements FactoryBean<Boy> {
@Override
public Boy getObject() throws Exception {
return new Lad("niulang");
}
@Override
public Class<?> getObjectType() {
return Boy.class;
}
}
<bean name="boyService2" class="edu.demo.spring.instantiate.BoyFactoryBean">
</bean>
如果要獲取BoyFactoryBean自身,需要加上"&"字首,否則返回的是getObject中的bean,這是由FactoryBean建立的bean例項
Object lsfb2 = context.getBean("boyService2");
System.out.println(lsfb2);
Object lsfb4 = context.getBean("&boyService2");
System.out.println(lsfb4);
BoyFactoryBean lsfb = (BoyFactoryBean) context.getBean("&boyService2");
System.out.println(lsfb);
System.out.println(lsfb.getObject());
分別輸出如下:
例項化bean的流程
從AbstractApplicationContext類中的refresh()方法看起,這裡有個步驟,是提前例項化一些單例bean:
//完成bean工廠的初始化,初始化所有非懶載入的單例bean
finishBeanFactoryInitialization(beanFactory);
點進去檢視具體的實現:
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
//例項化型別轉換服務
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
//確保beanFacotory持有嵌入值的解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 提前例項化LoadTimeWeaverAware beans
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// 凍結配置,要進行例項化了,bean定義資訊就不能進行更改了
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// 例項化單例bean
beanFactory.preInstantiateSingletons();
}
然後會進入preInstantiateSingletons方法:
/** 按照註冊順序存放的bean定義名稱集合 */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 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.
//獲取到所有的bean定義名稱
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
根據上面的程式碼可以看到,這個方法剛一進來,就獲取所有的bean定義名稱,這個bean定義的list使用了volatile關鍵字進行修飾,關於volatile不清楚的可以看下之前執行緒方面的文章。
// Trigger initialization of all non-lazy singleton beans...
//觸發所有非懶載入單例bean的初始化
for (String beanName : beanNames) {
//獲取合併之後的bean定義資訊
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果bean定義不是抽象的,並且是單例的,不是懶載入的,就繼續執行
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//如果是工廠bean就繼續執行,否則直接執行getBean方法
if (isFactoryBean(beanName)) {
//獲取bean,這裡的bean是一個工廠bean
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());
}
//如果這個bean急需例項化,就呼叫getBean方法
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//獲取普通bean
getBean(beanName);
}
}
}
FactoryBean是什麼,上面已經有了簡單的使用,FactoryBean雖然也是一個bean,但是它是一個可以生產bean的bean。如果直接使用getBean獲取的是它生產的bean,所以需要使用getBean(& + beanName)才能獲取這個工廠bean。
doGetBean方法介紹
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {}
這裡傳過來了四個引數,第一個引數name就是bean定義的名稱,requiredType是bean所需要的型別,args是顯式傳過來的引數,typeCheckOnly是否型別檢查。
args指的就是下面程式碼中的引數:
ConstructorBean constructorBean = (ConstructorBean) context.getBean("constructorBean", new Object[]{1,2,3});
使用剛剛上面的示例,然後debug到doGetBean方法可以看到:
進入方法的第一步就執行了transformedBeanName方法:
String beanName = transformedBeanName(name);
Object bean;
這個transformedBeanName方法就是獲取到標準的bean定義名稱,什麼是標準的bean定義名稱呢?因為在配置bean定義的時候,可以給這個bean定義一些別名。
當使用getBean("別名")也是可以獲取到這個bean定義的。主要的原因就是底層使用了aliasMap,這個aliasMap的key值就是別名,value值就是真正的bean定義名稱。
/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
/**
* Return the bean name, stripping out the factory dereference prefix if necessary,
* and resolving aliases to canonical names.
* @param name the user-specified name
* @return the transformed bean name
*/
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
這裡又呼叫了BeanFactoryUtils.transformedBeanName和canonicalName兩個方法:
/**
* 返回bean名稱,必要時去掉工廠解引用字首
* @param name the name of the bean
* @return the transformed name
* @see BeanFactory#FACTORY_BEAN_PREFIX
*/
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
//如果bean名稱不包含&字首,就直接返回
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
//去除bean名稱的解引用字首,也就是&字首
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
/**
* 這個方法的作用,就是獲取到真正的bean名稱
* @param name the user-specified name
* @return the transformed name
*/
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
canonicalName裡面使用了do...while迴圈來獲取真正的bean名稱,下面來個小例子看一下:
<bean id="constructorBean" name="bean1,bean2,bean3,bean4" class="edu.demo.spring.instantiate.ConstructorBean">
<constructor-arg index="0" value="翠花" />
<constructor-arg index="1" value="18" />
</bean>
<alias name="bean2" alias="a"/>
ConstructorBean constructorBean = (ConstructorBean) context.getBean("a");
上面給constructorBean配置了4個別名bean1,bean2,bean3,bean4,而且給別名bean2又配置了一個別名a,也就是別名的別名。
debug後可以看到,這裡傳過來的就是別名bean2的別名a:
下面的圖中,展示了bean定義別名的aliasMap:
現在清楚這裡為啥使用do...while迴圈來獲取標準的bean名稱了嗎,就是因為bean定義的別名,也可以有別名。當resolvedName為空,也就是說沒有別名了,就會跳出迴圈,獲取到真正的bean名稱了。
接下來使用if...else分成了兩個部分,先來看下第一部分:
// Eagerly check singleton cache for manually registered singletons.
//從快取中獲取已經例項化的單例bean
Object sharedInstance = getSingleton(beanName);
//如果bean例項存在且顯式傳過來的引數是空的就執行下面的程式碼
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//這裡,是判斷這個bean是不是FactoryBean,如果是FactoryBean,那麼就要從FactoryBean中建立一個例項
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
下面先看下getSingleton這個方法:
/** 單例bean的快取 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 單例工廠的快取 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 預載入的單例bean的快取 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先從單例bean的快取中獲取bean例項
Object singletonObject = this.singletonObjects.get(beanName);
//如果沒有獲取到並且這個bean正在建立中就執行下面的內容
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//加鎖
synchronized (this.singletonObjects) {
//從預載入的單例bean的快取中獲取bean例項
singletonObject = this.earlySingletonObjects.get(beanName);、
//如果還是沒有獲取到,而且是需要建立早期的引用的
if (singletonObject == null && allowEarlyReference) {
//從beanName中獲取單例工廠
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//如果工廠不為空
if (singletonFactory != null) {
//獲取bean
singletonObject = singletonFactory.getObject();
//放入預載入的單例bean的快取中
this.earlySingletonObjects.put(beanName, singletonObject);
//把bean從singletonFactories中移除,
//因為已經在上面加入到earlySingletonObjects了,所以singletonFactories就不需要了
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
如果上面的方式沒有獲取到bean例項,那麼就走下面的else方法:
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
首先這裡,是判斷原型bean是否已經在構建中了,來檢測迴圈依賴的,比如建立bean1的時候需要依賴bean2,而建立bean2的過程中又依賴bean1,那麼這樣就會丟擲異常。
下面的程式碼,就是判斷父工廠的:
// Check if bean definition exists in this factory.
//首先,獲取父工廠
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果父工廠不為空,並且本地又不包含這個bean定義,那就從父工廠中獲取
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
//這一步就是還原原來的bean名稱,因為有factoryBean的存在,
//上面把它的字首去掉,這裡要加回來
String nameToLookup = originalBeanName(name);
//下面就是通過父類去建立bean例項
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
從上面的程式碼可以看到,parentBeanFactory.getBean,這裡又使用了getBean方法,可見也是遞迴呼叫。
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
上面的程式碼,是判斷,如果這裡不僅僅是做型別檢查,那這裡就記錄一下,記錄該bean已經被建立了。下面是markBeanAsCreated方法:
/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
/** Names of beans that have already been created at least once. */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
protected void markBeanAsCreated(String beanName) {
//首先,判斷已經建立的bean集合中是否包含該bean
if (!this.alreadyCreated.contains(beanName)) {
//加鎖
synchronized (this.mergedBeanDefinitions) {
//再次判斷,雙重檢鎖
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
//這裡,是把合併的bean定義清除掉,讓bean定義重新合併,
//為了防止這個bean定義發生了變化
clearMergedBeanDefinition(beanName);
//把beanName加入到已經建立的集合中
this.alreadyCreated.add(beanName);
}
}
}
}
然後再次進入下面的程式碼:
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//獲取依賴的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
//迴圈遍歷依賴的bean
for (String dep : dependsOn) {
//判斷是不是迴圈依賴,是的話就丟擲異常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//註冊依賴的bean
registerDependentBean(dep, beanName);
try {
//獲取到依賴的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
這裡先是獲取合併後的bean定義,然後檢測該bean是否是抽象的,如果是的話,就會丟擲異常,這個判斷在checkMergedBeanDefinition方法內。
然後是看這個bean是否依賴了其他bean,如果有依賴,就把依賴的bean註冊到一個依賴的map中,然後呼叫getBean方法,先把依賴的bean例項化。
最後,如果上面都判斷結束,還是沒有獲取到bean例項的話,就執行下面的程式碼來建立bean例項:
// Create bean instance.
// Scope的處理:單例、原型、其他
//判斷是否單例
if (mbd.isSingleton()) {
//獲取單例bean,如果獲取不到就進行建立,然後快取到單例bean的集合中
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
//進行工廠bean的處理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//原型bean的處理
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
//多例bean的迴圈依賴檢查,並且做記錄
beforePrototypeCreation(beanName);
//建立bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//釋放迴圈依賴檢查的記錄
afterPrototypeCreation(beanName);
}
//進行工廠bean的處理
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//其他範圍bean的處理
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
//迴圈依賴檢查,並且做記錄
beforePrototypeCreation(beanName);
try {
//建立bean
return createBean(beanName, mbd, args);
}
finally {
//釋放迴圈依賴檢查的記錄
afterPrototypeCreation(beanName);
}
});
//進行工廠bean的處理
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
上面的建立,分成了三個部分,分別是單例、多例和其他範圍的bean,大致的處理過程是一樣的,都呼叫了createBean方法進行建立。
getSingleton方法
下面來看下單例bean的getSingleton方法:
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {}
這個方法用來獲取單例bean,而且會呼叫建立bean的方法。
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
}
首先進行了加鎖,然後從singletonObjects中獲取單例bean,singletonObjects上面已經說過,裡面存放了已經例項化的單例bean集合,這裡先從singletonObjects獲取,如果獲取不到,再進行建立。
/** Flag that indicates whether we're currently within destroySingletons. */
private boolean singletonsCurrentlyInDestruction = false;
/** Collection of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;
//如果獲取不到該單例bean,那麼就進行建立
if (singletonObject == null) {
//判斷該單例bean是否正在銷燬,是的話就拋異常
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//單例bean建立之前的處理,也是進行記錄
beforeSingletonCreation(beanName);
//是否新建立的單例bean
boolean newSingleton = false;
//記錄在建立過程中產生的異常,可能是的,這個我猜的,哈哈
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
}
然後看下beforeSingletonCreation這個方法
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
進行了判斷和新增,inCreationCheckExclusions是排除的bean名稱集合,也就是說這個bean不會被建立。singletonsCurrentlyInCreation記錄當前正在建立的bean名稱。
下面就是進行建立的程式碼:
try {
//singletonFactory就是執行上面的建立bean程式碼
singletonObject = singletonFactory.getObject();
//建立完成後,標誌為新的單例bean
newSingleton = true;
}
然後下面的程式碼就是進行一些快取:
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//移除記錄
afterSingletonCreation(beanName);
}
//如果是新的單例bean,就進行一些快取
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
看下afterSingletonCreation方法,就是把當前的bean從正在建立的集合中移除掉
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
然後下面就是快取的方法了:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
這個方法就比較簡單了,把已經例項化的單例bean加入到singletonObjects集合,因為已經例項化了,所以從singletonFactories和earlySingletonObjects中移除了,而且還加入到了registeredSingletons集合中。
原型bean
下面來看下原型bean的處理:
/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
protected void afterPrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal instanceof String) {
this.prototypesCurrentlyInCreation.remove();
}
else if (curVal instanceof Set) {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.remove(beanName);
if (beanNameSet.isEmpty()) {
this.prototypesCurrentlyInCreation.remove();
}
}
}
從上面的原始碼,可以看到,prototypesCurrentlyInCreation使用到了ThreadLocal,可以避免執行緒重複建立bean,afterPrototypeCreation是把這個標誌給移除掉。而scope和原型bean這塊的處理是一樣的。
getObjectForBeanInstance方法
最後呢,還有一個方法沒有看,下面就來看下getObjectForBeanInstance這個方法吧。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {}
這裡傳來了四個引數,beanInstance是bean例項,name是原始的bean名稱,也就是可能包含&字首,beanName是標準的bean名稱,mbd是合併之後的bean定義資訊。
/** Package-visible field for caching if the bean is a factory bean. */
@Nullable
volatile Boolean isFactoryBean;
//判斷是不是工廠bean
if (BeanFactoryUtils.isFactoryDereference(name)) {
//如果是NullBean,直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果不是FactoryBean型別,直接丟擲異常
//是工廠bean,但是不是FactoryBean型別
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
//設定isFactoryBean標誌,標誌該bean是工廠bean
if (mbd != null) {
mbd.isFactoryBean = true;
}
//返回bean例項
return beanInstance;
}
判斷是不是工廠bean的方法,比較簡單,判斷是不是以&開頭的:
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
如果當前bean例項不是FactoryBean型別,直接返回
// 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;
}
如果上面都沒有獲取到bean例項,則執行下面的程式碼:
/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//從快取中獲取bean
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.
//如果bean定義為空,且beanDefinitionMap中包含該bean名稱,則獲取合併後的bean定義
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是使用者自定義的bean
boolean synthetic = (mbd != null && mbd.isSynthetic());
//從FactoryBean中獲取bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
getCachedObjectForFactoryBean方法比較簡單,直接從快取的map中獲取即可:
@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
再然後就是getObjectFromFactoryBean,從FactoryBean中來獲取物件:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess)
這裡傳過來三個引數,factory就是上面傳過來的factoryBean,beanName就是配置裡面定義的bean名稱,shouldPostProcess的意思是:是否允許bean進行後置處理。
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
}
}
首先上來就是判斷,這個factory是不是單例的,單例bean的集合中是否包含這個bean名稱,如果都滿足就執行下面的程式碼。
/** 由FactoryBean建立的單例物件的快取:物件的FactoryBean名稱 */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
//首先從快取中獲取
Object object = this.factoryBeanObjectCache.get(beanName);
//如果快取中不存在就繼續執行
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
//再次從快取中獲取,由於迴圈引用可能導致這個bean已經在快取中了
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
//獲取到了就直接賦值
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
//當前bean正在建立直接返回,暫時不做後置處理
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
//迴圈依賴檢查,做記錄
beforeSingletonCreation(beanName);
try {
//對這個bean做後置處理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
//迴圈依賴檢查,移除
afterSingletonCreation(beanName);
}
}
//當前bean是否在單例bean的集合中,如果是的就快取
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
//返回bean例項
return object;
再然後就是else裡面的處理,程式碼量較少,if裡面已經有相同的程式碼了。
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
doGetObjectFromFactoryBean方法:
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
//進行許可權的驗證
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//這裡,直接呼叫了getObject方法
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
這部分的程式碼,就是從factoryBean中獲取到getObject裡面的bean例項。
建立例項流程圖
下面,根據上面的原始碼內容,做一個簡單的流程圖,方便進行總結和檢視:
到此,getBean相關的內容已經介紹完畢了,下面就是真正建立bean例項的過程了。文章旨在記錄學習內容和分享,如有不足還請見諒,文章中若有錯誤的地方,還望大佬不吝賜教,及時指正,共同學習,共同進步,互勉!