Spring
是一個開源的設計層面框架,解決了業務邏輯層和其他各層的鬆耦合問題,將面向介面的程式設計思想貫穿整個系統應用,同時它也是Java工作中
必備技能之一…
<!– more –>
前言
在 Spring解密 – XML解析 與 Bean註冊 中,講了 Bean的解析
,本章將詳細講解Spring中Bean的載入過程
,相比解析
而言,載入稍微複雜一點.
入口
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person.toString());
}
}
重點分析 context.getBean();
解密
在分析 Bean
的載入過程前,我們看看 BeanFactory
的由來,以及 getBean
所屬的類是誰。磨刀不誤砍柴工
BeanFactory 的由來
1.檢視getBean()
的原始碼,此處的 getBeanFactory()
是怎麼來的?
public class AbstractApplicationContext{
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
// getBeanFactory() 是怎麼來的?我們接著看
return getBeanFactory().getBean(name, requiredType);
}
}
2.應用程式的上下文
在 new ClassPathXmlApplicationContext("bean.xml");
中,跳轉到過載的構造方法中,我們會發現如下程式碼
public class ClassPathXmlApplicationContext {
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 解析 bean.xml 檔案
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
}
它的目的是將普通路徑解析為 類(classpath)
路徑資源名稱。多個配置檔案的情況下,後載入的 Bean
會覆蓋先前定義好的 Bean
,這樣做的目的是為了通過額外的XML檔案來特意重寫某個 Bean
。這裡我們可以看到呼叫了一個 refresh()
,它的作用是什麼呢?
3.初始化
重新整理容器
public class AbstractApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 準備重新整理上下文
prepareRefresh();
// 通知子類,重新整理內部 BeanFactory(建立 BeanFactory 的入口)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
}
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 跟蹤該方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
}
初次載入完 bean.xml
後,肯定會進入到 refresh()
方法中,這個時候會做容器初始化的工作,也就是 標籤解析、Bean載入
等等工作,由於本章重點介紹 Bean載入
,所以只貼了少量程式碼(看官莫急)
建立
DefaultListableBeanFactory
public class AbstractRefreshableApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
// 判斷是否存在
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 建立 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
// 然後賦值給 beanFactory 變數
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
// 提取 BeanFactory
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call `refresh` before accessing beans via the ApplicationContext");
}
return this.beanFactory;
}
}
}
從上面的程式碼塊中,我們可以看到 如果已經存在 beanFactory,將銷燬舊的例項,然後在建立新的 DefaultListableBeanFactory
,最後 getBeanFactory()
就可以正常使用了。
Bean 載入
整個 Bean
的裝載過程中,重點圍繞 AbstractBeanFactory
,只要把它搞定剩下的就輕鬆了
public abstract class AbstractBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 別名轉換
final String beanName = transformedBeanName(name);
Object bean;
// 檢查快取中是否存在 該 Bean 的單例(Bean預設的Scope = singleton)
// 比如容器初始化的時候或者其他地方呼叫過getBean,已經完成了初始化
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean `" + beanName +
"` that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean `" + beanName + "`");
}
}
// 返回例項,FactoryBean 的情況下,並不是直接返回例項本身而是返回指定方法返回的例項
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 存在迴圈依賴則報錯
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 判斷工廠中是否含有當前 Bean 的定義
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果沒有,查詢父工廠
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// 執行帶有 args 引數的 getBean 方法
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 如果沒有引數,執行標準的 getBean 方法
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) { // 如果不是做型別檢查,則需要標記此 Bean 正在建立之中
markBeanAsCreated(beanName);
}
try {
// 將儲存XML配置檔案的GernericBeanDefinition轉換成RootBeanDefinition,如果BeanName是子Bean的話會合並父類的相關屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 獲取依賴的 Bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between `" + beanName + "` and `" + dep + "`");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// 終於開始建立 Bean 例項了,如果是單例的,那麼會建立一個單例的匿名工廠,
// 如果是原型模式的,則不需要建立單例的工廠的,其他的如 request、session 作用域的,則根據自身的需要
if (mbd.isSingleton()) {
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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It`s a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final 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 {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
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);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 型別檢查,如果不能進行型別轉換,則丟擲異常
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean `" + name + "` to required type `" +
ClassUtils.getQualifiedName(requiredType) + "`", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
}
整個程式碼塊的內容還是不少的,接下來我們一步一步的分析。
轉換 BeanName
final String beanName = transformedBeanName(name);
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
去除 FactoryBean
的修飾符,最終取指定 alias
所表示的 beanName
。因為有可能獲取到以 & 開頭的 FactoryBean
,所以要進行轉化(關於 BeanFactory
和 FactoryBean
後面會進行區分)
載入單例
檢查快取中是否存在 該 Bean
的單例(Bean預設的Scope = singleton)
,如容器初始化的時候或者其他地方已經呼叫過 getBean()
完成了初始化
Object sharedInstance = getSingleton(beanName);
快取載入 Bean
預設在裝載 Bean
的時候會先去檢查 singletonObjects
是否存在,如果存在直接提取快取的。
public class DefaultSingletonBeanRegistry {
/** 儲存 BeanName 和建立 bean 例項之間的關係 bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 儲存 BeanName 和建立 bean 例項的工廠之間的關係 bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 儲存 BeanName 和建立 bean 例項之間的關係 bean name --> bean instance */
/** 與 singletonObjects 不同的是當一個單例 bean 被放到裡面後,那麼在 bean 在建立過程中,就可以通過 getBean 方法獲取到,可以用來檢測迴圈引用。 **/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 儲存當前所有已註冊的 bean */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 嘗試從快取獲取例項
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 若該 bean 正在載入則不處理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 存入到快取中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
構建例項(無快取情況)
快取中沒有,那就當場構建一個 bean
出來,可以看到 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
有兩個引數,其中的 ObjectFactory
是怎麼來的呢? 接著往下看
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 記錄載入狀態,,以便對迴圈依賴進行檢測
beforeSingletonCreation(beanName);
singletonObject = singletonFactory.getObject();
// 移除載入狀態
afterSingletonCreation(beanName);
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
構建
ObjectFactory
此處與其說是構建 ObjectFactory
,不如說是在建立一個單例 Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 對 JDK8 lambda 表示式熟悉的小夥伴就不會陌生了
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 劃重點了
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
建立 Bean
public class AbstractAutowireCapableBeanFactory {
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean `" + beanName + "`");
}
RootBeanDefinition mbdToUse = mbd;
// 首先判斷需要建立的bean是否可以被例項化,這個類是否可以通過類裝載器來載入。
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 準備方法覆蓋
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 用 BeanPostProcessors 返回代理來替代真正的例項(如果 Bean 配置了 PostProcessor,那麼這裡返回的是一個代理)
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 重點來了
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean `" + beanName + "`");
}
return beanInstance;
}
catch (BeanCreationException ex) {
// A previously detected exception with proper bean creation context already...
throw ex;
}
catch (ImplicitlyAppearedSingletonException ex) {
// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
}
在建立 Bean
之前,Spring
還做了不少工作。
- 判斷建立的
bean
是否可以被例項化,這個類是否可以通過ClassLoader
來載入,根據設定的class
屬性或根據className
來解析class
。 - 對覆蓋進行標記並驗證,在
Spring
配置中存在lookup-mothod
和replace-method
的,這兩個配置的載入時將配置統一存放在BeanDefinition
中的methodOverrides
屬性裡,這個方法的操作也是針對於這兩個配置的; - 應用初始化前的後處理器,最後建立
bean
。在createBean()
方法裡執行完resolveBeforeInstantiation
方法後,如果建立了代理且不為空的話就直接返回,否則需要進行常規bean
的建立,這個建立過程是在doCreateBean
中完成的
初始化 Bean
上面 createBean
交給了 doCreateBean
來建立 bean
(上面還有一個重要的方法getObjectForBeanInstance,在後面分析)
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 例項化 Bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 根據指定 bean 使用相應策略建立例項(正確情況會呼叫無參建構函式)
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 獲取例項化好的 Bean(Person person = new Person()),此處還未進行賦值
final Object bean = instanceWrapper.getWrappedInstance();
// 獲得例項化好的 class
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 記錄建立 Bean 的 ObjectFactory,初始化前呼叫 post-processors,可以讓我們在 bean 例項化之前做一些定製操作
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 檢測迴圈依賴,是否需要提早初始化(只能解決單例Bean)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean `" + beanName +
"` to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化bean例項。
Object exposedObject = bean;
try {
// 在這個方法裡面初始化物件,配置 xml 中的各種屬性
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name `" + beanName + "` has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"`getBeanNamesOfType` with the `allowEagerInit` flag turned off, for example.");
}
}
}
}
// 用於銷燬方法
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
上面原始碼完成的操作可以概括為以下幾點
-
RootBeanDefinition
是不是單例,如果是單例先移除快取 - 例項化
bean
,將RootBeanDefinition
轉換為BeanWrapper
- 使用
MergedBeanDefinitionPostProcessor
,Autowired註解
就是通過此方法實現型別的預解析; - 解決迴圈依賴問題
- 在
populateBean()
中填充屬性,配置在XML
中的各種屬性 - 註冊到
DisposableBean
中 - 完成建立並返回
Bean
的例項
接下來我們看下 Spring
是如何建立 bean
例項的。跟蹤 createBeanInstance()
方法
建立Bean例項
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 獲取 beanClass , 要先確保 Bean 是正確的,已經解析到當前節點了
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn`t public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 若工廠方法不為空則使用工廠方法初始化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 如果已經解析過則使用解析好的構造方法不需要再次鎖定
if (resolved) {
if (autowireNecessary) {
// 構造方法自動注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用預設構造方法
return instantiateBean(beanName, mbd);
}
}
// 根據引數解析構造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 沒有特殊處理的情況下,只需使用無引數的建構函式。
return instantiateBean(beanName, mbd);
}
可以看出如果在 RootBeanDefinition
中存在 factoryMethodName
屬性,或者說配置檔案中配置了 factory-method
,那麼 Spring
會嘗試使用 instantiateUsingFactoryMethod(beanName, mbd, args)
方法根據 RootBeanDefinition
中的配置生成bean例項。然後再解析構造方法並進行例項化,Spring
會根據引數及型別判斷使用哪個構造方法進行例項化。判斷呼叫哪個構造方法的過程會採用快取機制,如果已經解析過則不需要重複解析而是從 RootBeanDefinition
中的屬性 resolvedConstructorOrFactoryMethod
快取的值去取,否則需再次解析。
populateBean 屬性注入
這塊程式碼比較多,有興趣請自行跟進,就不貼出來了
在 populateBean
方法的中的主要處理流程:
-
InstantiationAwareBeanPostProcessor
處理器的postProcessAfterInstantiation
方法控制程式是否繼續填充屬性; - 根據注入型別提取依賴的
bean
,並存入PropertyValues
中; -
InstantiationAwareBeanPostProcessor
處理器的postProcessPropertyValues
方法對屬性在填充前再次處理(主要還是驗證屬性); - 將所有
PropertyValues
中的屬性填充到BeanWrapper
中;
initializeBean 初始化Bean
學過 Spring
的都知道 bean
配置時有一個 init-method
屬性,這個屬性的作用是在 bean
例項化前呼叫 init-method
指定的方法進行需要的操作,現在就進入這個方法了;Spring
執行過 bean
的例項化,並且進行屬性填充後,就會呼叫使用者設定的初始化方法。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 特殊bean處理
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 呼叫配置的 init-method
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
最後載入完 Bean
並執行完初始化操作後,一個 bean
的載入基本就結束了。
增強的 Bean
通過上面的描述,我們已經知道了一個的 Bean
是如何初始化的,已經具備普通 Bean
的功能。但是 Spring
還提供了一種增強的 Bean(FactoryBean)
,具備 factory
能力的 Bean
,這個能力主要在 getObjectForBeanInstance
得到。
public class AbstractBeanFactory {
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果想要獲取 FactoryBean 本身,那麼 beanInstance 必須是 FactoryBean 的例項
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 如果 instance 不是 FactoryBean 例項,或者想要獲取的就是 FactoryBean 例項,那麼直接返回就好
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 獲取快取的例項
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 快取中沒有物件,那麼從頭準備 bean defition 例項化一個
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 在這裡面獲得最終的FactoryBean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
}
關於 BeanFactory
和 FactoryBean
的區別:
-
BeanFactory: 容器的基本介面,是一個工廠,用來生產
Bean
-
FactoryBean: 是一個特殊的
Bean
,可以當作工廠使用的Bean
迴圈依賴
上面有簡單提到過 迴圈依賴(只有在單例情況下才會嘗試解決迴圈依賴)。 無法解決就只能丟擲 BeanCurrentlyInCreationException
異常
構造器迴圈依賴
無法解決,只能丟擲 BeanCurrentlyInCreationException
異常
<bean id="A" class="com.battcn.A">
<constructor-arg index="0" ref="B" />
</bean>
<bean id="B" class="com.battcn.B">
<constructor-arg index="0" ref="C" />
</bean>
<bean id="C" class="com.battcn.C">
<constructor-arg index="0" ref="A" />
</bean>
setter 迴圈依賴
Spring
容器提前暴露了剛好完成的構造器注入,但未完成其他步驟 (如 setter 注入
的 bean
)。只能解決單例作用域的 bean
迴圈依賴。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
prototype 範圍的依賴處理
Spring
容器無法完成依賴注入,因為 Spring
容器不會快取 prototype
作用域的 bean
,因此無法提前暴露一個建立中的 bean
。
<bean id="A" class="com.battcn.A" scope="prototype">
<property name="B" ref="B" />
</bean>
<bean id="B" class="com.battcn.B" scope="prototype">
<property name="C" ref="C" />
</bean>
<bean id="C" class="com.battcn.C" scope="prototype">
<property name="A" ref="A" />
</bean>
總結
熬過幾個無人知曉的秋冬春夏,撐過去一切都會順著你想要的方向走…
說點什麼
全文程式碼:https://gitee.com/battcn/battcn-spring-source/tree/master/Chapter4
- 個人QQ:1837307557
- battcn開源群(適合新手):391619659
微信公眾號:battcn
(歡迎調戲)