Spring框架系列(8) - Spring IOC實現原理詳解之Bean實例化(生命週期,循環依賴等)

語言: CN / TW / HK

上文,我們看了IOC設計要點和設計結構;以及Spring如何實現將資源配置(以xml配置為例)通過加載,解析,生成BeanDefination並註冊到IoC容器中的;容器中存放的是Bean的定義即BeanDefinition放到beanDefinitionMap中,本質上是一個ConcurrentHashMap<String, Object>;並且BeanDefinition接口中包含了這個類的Class信息以及是否是單例等。那麼如何從BeanDefinition中實例化Bean對象呢,這是本文主要研究的內容?@pdai

引入

上文,我們看了IOC設計要點和設計結構;以及Spring如何實現將資源配置(以xml配置為例)通過加載,解析,生成BeanDefination並註冊到IoC容器中的;容器中存放的是Bean的定義即BeanDefinition放到beanDefinitionMap中,本質上是一個ConcurrentHashMap<String, Object>;並且BeanDefinition接口中包含了這個類的Class信息以及是否是單例等。那麼如何從BeanDefinition中實例化Bean對象呢?

本文主要研究如何從IOC容器已有的BeanDefinition信息,實例化出Bean對象;這裏還會包括三塊重點內容: + BeanFactory中getBean的主體思路 + Spring如何解決循環依賴問題 + Spring中Bean的生命週期

BeanFactory中getBean的主體思路

上文中我們知道BeanFactory定義了Bean容器的規範,其中包含根據bean的名字, Class類型和參數等來得到bean實例。

java // 根據bean的名字和Class類型等來得到bean實例 Object getBean(String name) throws BeansException; Object getBean(String name, Class requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

初步的思考

上文我們已經分析了IoC初始化的流程,最終的將Bean的定義即BeanDefinition放到beanDefinitionMap中,本質上是一個ConcurrentHashMap<String, Object>;並且BeanDefinition接口中包含了這個類的Class信息以及是否是單例等;

這樣我們初步有了實現Object getBean(String name)這個方法的思路:

  • 從beanDefinitionMap通過beanName獲得BeanDefinition
  • 從BeanDefinition中獲得beanClassName
  • 通過反射初始化beanClassName的實例instance
  • 構造函數從BeanDefinition的getConstructorArgumentValues()方法獲取
  • 屬性值從BeanDefinition的getPropertyValues()方法獲取
  • 返回beanName的實例instance

由於BeanDefinition還有單例的信息,如果是無參構造函數的實例還可以放在一個緩存中,這樣下次獲取這個單例的實例時只需要從緩存中獲取,如果獲取不到再通過上述步驟獲取。

(PS:如上只是我們初步的思路,而Spring還需要考慮各種設計上的問題,比如beanDefinition中其它定義,循環依賴等;所以我們來看下Spring是如何是如何實現的)

Spring中getBean的主體思路

BeanFactory實現getBean方法在AbstractBeanFactory中,這個方法重載都是調用doGetBean方法進行實現的:

java public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); }

我們來看下doGetBean方法(這個方法很長,我們主要看它的整體思路和設計要點):

```java // 參數typeCheckOnly:bean實例是否包含一個類型檢查 protected T doGetBean( String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

// 解析bean的真正name,如果bean是工廠類,name前綴會加&,需要去掉 String beanName = transformedBeanName(name); Object beanInstance;

// Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 無參單例從緩存中獲取 beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); }

else { // 如果bean實例還在創建中,則直接拋出異常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }

// 如果 bean definition 存在於父的bean工廠中,委派給父Bean工廠獲取
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
  // Not found -> check parent.
  String nameToLookup = originalBeanName(name);
  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);
  }
}

if (!typeCheckOnly) {
  // 將當前bean實例放入alreadyCreated集合裏,標識這個bean準備創建了
  markBeanAsCreated(beanName);
}

StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
    .tag("beanName", name);
try {
  if (requiredType != null) {
    beanCreation.tag("beanType", requiredType::toString);
  }
  RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  checkMergedBeanDefinition(mbd, beanName, args);

  // 確保它的依賴也被初始化了.
  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);
      try {
        getBean(dep); // 初始化它依賴的Bean
      }
      catch (NoSuchBeanDefinitionException ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
      }
    }
  }

  // 創建Bean實例:單例
  if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
      try {
        // 真正創建bean的方法
        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;
      }
    });
    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  }
  // 創建Bean實例:原型
  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);
    }
    beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
  }
  // 創建Bean實例:根據bean的scope創建
  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 {
          return createBean(beanName, mbd, args);
        }
        finally {
          afterPrototypeCreation(beanName);
        }
      });
      beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    }
    catch (IllegalStateException ex) {
      throw new ScopeNotActiveException(beanName, scopeName, ex);
    }
  }
}
catch (BeansException ex) {
  beanCreation.tag("exception", ex.getClass().toString());
  beanCreation.tag("message", String.valueOf(ex.getMessage()));
  cleanupAfterBeanCreationFailure(beanName);
  throw ex;
}
finally {
  beanCreation.end();
}

}

return adaptBeanInstance(name, beanInstance, requiredType); } ```

這段代碼很長,主要看我加中文註釋的方法即可。

  • 解析bean的真正name,如果bean是工廠類,name前綴會加&,需要去掉
  • 無參單例先從緩存中嘗試獲取
  • 如果bean實例還在創建中,則直接拋出異常
  • 如果bean definition 存在於父的bean工廠中,委派給父Bean工廠獲取
  • 標記這個beanName的實例正在創建
  • 確保它的依賴也被初始化
  • 真正創建
  • 單例時
  • 原型時
  • 根據bean的scope創建

重點:Spring如何解決循環依賴問題

首先我們需要説明,Spring只是解決了單例模式下屬性依賴的循環問題;Spring為了解決單例的循環依賴問題,使用了三級緩存。

Spring單例模式下的屬性依賴

先來看下這三級緩存

```java /* Cache of singleton objects: bean name --> bean instance / private final Map singletonObjects = new ConcurrentHashMap(256);

/* Cache of early singleton objects: bean name --> bean instance / private final Map earlySingletonObjects = new HashMap(16);

/* Cache of singleton factories: bean name --> ObjectFactory / private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

```

  • 第一層緩存(singletonObjects):單例對象緩存池,已經實例化並且屬性賦值,這裏的對象是成熟對象
  • 第二層緩存(earlySingletonObjects):單例對象緩存池,已經實例化但尚未屬性賦值,這裏的對象是半成品對象
  • 第三層緩存(singletonFactories): 單例工廠的緩存

如下是獲取單例中

java protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Spring首先從singletonObjects(一級緩存)中嘗試獲取 Object singletonObject = this.singletonObjects.get(beanName); // 若是獲取不到而且對象在建立中,則嘗試從earlySingletonObjects(二級緩存)中獲取 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //若是仍是獲取不到而且容許從singletonFactories經過getObject獲取,則經過singletonFactory.getObject()(三級緩存)獲取 singletonObject = singletonFactory.getObject(); //若是獲取到了則將singletonObject放入到earlySingletonObjects,也就是將三級緩存提高到二級緩存中 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }

補充一些方法和參數

  • isSingletonCurrentlyInCreation():判斷當前單例bean是否正在建立中,也就是沒有初始化完成(好比A的構造器依賴了B對象因此得先去建立B對象, 或則在A的populateBean過程當中依賴了B對象,得先去建立B對象,這時的A就是處於建立中的狀態。)
  • allowEarlyReference :是否容許從singletonFactories中經過getObject拿到對象

分析getSingleton()的整個過程,Spring首先從一級緩存singletonObjects中獲取。若是獲取不到,而且對象正在建立中,就再從二級緩存earlySingletonObjects中獲取。若是仍是獲取不到且容許singletonFactories經過getObject()獲取,就從三級緩存singletonFactory.getObject()(三級緩存)獲取,若是獲取到了則從三級緩存移動到了二級緩存。

從上面三級緩存的分析,咱們能夠知道,Spring解決循環依賴的訣竅就在於singletonFactories這個三級cache。這個cache的類型是ObjectFactory,定義以下:

java public interface ObjectFactory<T> { T getObject() throws BeansException; }

在bean建立過程當中,有兩處比較重要的匿名內部類實現了該接口。一處是Spring利用其建立bean的時候,另外一處就是:

java addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); }});

此處就是解決循環依賴的關鍵,這段代碼發生在createBeanInstance以後,也就是説單例對象此時已經被建立出來的。這個對象已經被生產出來了,雖然還不完美(尚未進行初始化的第二步和第三步),可是已經能被人認出來了(根據對象引用能定位到堆中的對象),因此Spring此時將這個對象提早曝光出來讓你們認識,讓你們使用。

好比“A對象setter依賴B對象,B對象setter依賴A對象”,A首先完成了初始化的第一步,而且將本身提早曝光到singletonFactories中,此時進行初始化的第二步,發現本身依賴對象B,此時就嘗試去get(B),發現B尚未被create,因此走create流程,B在初始化第一步的時候發現本身依賴了對象A,因而嘗試get(A),嘗試一級緩存singletonObjects(確定沒有,由於A還沒初始化徹底),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,因為A經過ObjectFactory將本身提早曝光了,因此B可以經過ObjectFactory.getObject拿到A對象(半成品),B拿到A對象後順利完成了初始化階段一、二、三,徹底初始化以後將本身放入到一級緩存singletonObjects中。此時返回A中,A此時能拿到B的對象順利完成本身的初始化階段二、三,最終A也完成了初始化,進去了一級緩存singletonObjects中,並且更加幸運的是,因為B拿到了A的對象引用,因此B如今hold住的A對象完成了初始化。

Spring為何不能解決非單例屬性之外的循環依賴?

通過以下幾個問題,輔助我們進一步理解。

Spring為什麼不能解決構造器的循環依賴?

構造器注入形成的循環依賴: 也就是beanB需要在beanA的構造函數中完成初始化,beanA也需要在beanB的構造函數中完成初始化,這種情況的結果就是兩個bean都不能完成初始化,循環依賴難以解決。

Spring解決循環依賴主要是依賴三級緩存,但是的在調用構造方法之前還未將其放入三級緩存之中,因此後續的依賴調用構造方法的時候並不能從三級緩存中獲取到依賴的Bean,因此不能解決。

Spring為什麼不能解決prototype作用域循環依賴?

這種循環依賴同樣無法解決,因為spring不會緩存‘prototype’作用域的bean,而spring中循環依賴的解決正是通過緩存來實現的。

Spring為什麼不能解決多例的循環依賴?

多實例Bean是每次調用一次getBean都會執行一次構造方法並且給屬性賦值,根本沒有三級緩存,因此不能解決循環依賴。

那麼其它循環依賴如何解決?

那麼實際開發中,類似的依賴是如何解決?

  • 生成代理對象產生的循環依賴

這類循環依賴問題解決方法很多,主要有: 1. 使用@Lazy註解,延遲加載 2. 使用@DependsOn註解,指定加載先後關係 3. 修改文件名稱,改變循環依賴類的加載順序

  • 使用@DependsOn產生的循環依賴

這類循環依賴問題要找到@DependsOn註解循環依賴的地方,迫使它不循環依賴就可以解決問題。

  • 多例循環依賴

這類循環依賴問題可以通過把bean改成單例的解決。

  • 構造器循環依賴

這類循環依賴問題可以通過使用@Lazy註解解決。

重點:Spring中Bean的生命週期

Spring 只幫我們管理單例模式 Bean 的完整生命週期,對於 prototype 的 bean ,Spring 在創建好交給使用者之後則不會再管理後續的生命週期。

Spring 容器可以管理 singleton 作用域 Bean 的生命週期,在此作用域下,Spring 能夠精確地知道該 Bean 何時被創建,何時初始化完成,以及何時被銷燬。

而對於 prototype 作用域的 Bean,Spring 只負責創建,當容器創建了 Bean 的實例後,Bean 的實例就交給客户端代碼管理,Spring 容器將不再跟蹤其生命週期。每次客户端請求 prototype 作用域的 Bean 時,Spring 容器都會創建一個新的實例,並且不會管那些被配置成 prototype 作用域的 Bean 的生命週期。

瞭解 Spring 生命週期的意義就在於,可以利用 Bean 在其存活期間的指定時刻完成一些相關操作。這種時刻可能有很多,但一般情況下,會在 Bean 被初始化後和被銷燬前執行一些相關操作。

Spring Bean生命週期流程

在 Spring 中,Bean 的生命週期是一個很複雜的執行過程,我們可以利用 Spring 提供的方法定製 Bean 的創建過程。

Spring 容器中 Bean 的生命週期流程

  • 如果 BeanFactoryPostProcessor 和 Bean 關聯, 則調用postProcessBeanFactory方法.(即首先嚐試從Bean工廠中獲取Bean)
  • 如果 InstantiationAwareBeanPostProcessor 和 Bean 關聯,則調用postProcessBeforeInstantiation方法
  • 根據配置情況調用 Bean 構造方法實例化 Bean
  • 利用依賴注入完成 Bean 中所有屬性值的配置注入
  • 如果 InstantiationAwareBeanPostProcessor 和 Bean 關聯,則調用postProcessAfterInstantiation方法和postProcessProperties
  • 調用xxxAware接口 (上圖只是給了幾個例子)
  • 第一類Aware接口
    • 如果 Bean 實現了 BeanNameAware 接口,則 Spring 調用 Bean 的 setBeanName() 方法傳入當前 Bean 的 id 值。
    • 如果 Bean 實現了 BeanClassLoaderAware 接口,則 Spring 調用 setBeanClassLoader() 方法傳入classLoader的引用。
    • 如果 Bean 實現了 BeanFactoryAware 接口,則 Spring 調用 setBeanFactory() 方法傳入當前工廠實例的引用。
  • 第二類Aware接口
    • 如果 Bean 實現了 EnvironmentAware 接口,則 Spring 調用 setEnvironment() 方法傳入當前 Environment 實例的引用。
    • 如果 Bean 實現了 EmbeddedValueResolverAware 接口,則 Spring 調用 setEmbeddedValueResolver() 方法傳入當前 StringValueResolver 實例的引用。
    • 如果 Bean 實現了 ApplicationContextAware 接口,則 Spring 調用 setApplicationContext() 方法傳入當前 ApplicationContext 實例的引用。
    • ...
  • 如果 BeanPostProcessor 和 Bean 關聯,則 Spring 將調用該接口的預初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操作,此處非常重要,Spring 的 AOP 就是利用它實現的。
  • 如果 Bean 實現了 InitializingBean 接口,則 Spring 將調用 afterPropertiesSet() 方法。(或者有執行@PostConstruct註解的方法)
  • 如果在配置文件中通過 init-method 屬性指定了初始化方法,則調用該初始化方法。
  • 如果 BeanPostProcessor 和 Bean 關聯,則 Spring 將調用該接口的初始化方法 postProcessAfterInitialization()。此時,Bean 已經可以被應用系統使用了。
  • 如果在 <bean> 中指定了該 Bean 的作用範圍為 scope="singleton",則將該 Bean 放入 Spring IoC 的緩存池中,將觸發 Spring 對該 Bean 的生命週期管理;如果在 <bean> 中指定了該 Bean 的作用範圍為 scope="prototype",則將該 Bean 交給調用者,調用者管理該 Bean 的生命週期,Spring 不再管理該 Bean。
  • 如果 Bean 實現了 DisposableBean 接口,則 Spring 會調用 destory() 方法將 Spring 中的 Bean 銷燬;(或者有執行@PreDestroy註解的方法)
  • 如果在配置文件中通過 destory-method 屬性指定了 Bean 的銷燬方法,則 Spring 將調用該方法對 Bean 進行銷燬。

Bean的完整生命週期經歷了各種方法調用,這些方法可以劃分為以下幾類:(結合上圖,需要有如下頂層思維)

  • Bean自身的方法: 這個包括了Bean本身調用的方法和通過配置文件中<bean>的init-method和destroy-method指定的方法
  • Bean級生命週期接口方法: 這個包括了BeanNameAware、BeanFactoryAware、ApplicationContextAware;當然也包括InitializingBean和DiposableBean這些接口的方法(可以被@PostConstruct和@PreDestroy註解替代)
  • 容器級生命週期接口方法: 這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實現,一般稱它們的實現類為“後處理器”。
  • 工廠後處理器接口方法: 這個包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工廠後處理器接口的方法。工廠後處理器也是容器級的。在應用上下文裝配配置文件之後立即調用。

Spring Bean生命週期案例

我們通過一個例子來驗證上面的整個流程

定義Bean(這裏是User), 並讓它實現BeanNameAware,BeanFactoryAware,ApplicationContextAware接口和InitializingBean,DisposableBean接口:

```java package tech.pdai.springframework.entity;

import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware;

/ * @author pdai */ @Slf4j @ToString public class User implements BeanFactoryAware, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean { / * user's name. */ private String name;

/**
 * user's age.
 */
private int age;

/**
 * bean factory.
 */
private BeanFactory beanFactory;

/**
 * application context.
 */
private ApplicationContext applicationContext;

/**
 * bean name.
 */
private String beanName;

public User() {
    log.info("execute User#new User()");
}

public void setName(String name) {
    log.info("execute User#setName({})", name);
    this.name = name;
}

public void setAge(int age) {
    log.info("execute User#setAge({})", age);
    this.age = age;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    log.info("execute BeanFactoryAware#setBeanFactory");
    this.beanFactory = beanFactory;
}

@Override
public void setBeanName(String s) {
    log.info("execute BeanNameAware#setBeanName");
    this.beanName = s;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    log.info("execute ApplicationContextAware#setApplicationContext");
    this.applicationContext = applicationContext;
}

@Override
public void destroy() throws Exception {
    log.info("execute DisposableBean#destroy");
}

@Override
public void afterPropertiesSet() throws Exception {
    log.info("execute InitializingBean#afterPropertiesSet");
}


public void doInit() {
    log.info("execute User#doInit");
}

public void doDestroy() {
    log.info("execute User#doDestroy");
}

} ```

定義BeanFactoryPostProcessor的實現類

```java /* * @author pdai / @Slf4j @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    log.info("execute BeanFactoryPostProcessor#postProcessBeanFactory");
}

} ```

定義InstantiationAwareBeanPostProcessor的實現類

```java /* * @author pdai / @Slf4j @Component public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { log.info("execute InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation for {}", beanName); return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName); }

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    log.info("execute InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation for {}", beanName);
    return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    log.info("execute InstantiationAwareBeanPostProcessor#postProcessProperties for {}", beanName);
    return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
}

} ```

定義BeanPostProcessor的實現類

```java /* * @author pdai / @Slf4j @Component public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    log.info("execute BeanPostProcessor#postProcessBeforeInitialization for {}", beanName);
    return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    log.info("execute BeanPostProcessor#postProcessAfterInitialization for {}", beanName);
    return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

} ```

通過Java配置方式初始化Bean

```java /* * @author pdai / @Configuration public class BeansConfig {

@Bean(name = "user", initMethod = "doInit", destroyMethod = "doDestroy")
public User create() {
    User user = new User();
    user.setName("pdai");
    user.setAge(18);
    return user;
}

} ```

測試的主方法

```java /* * Cglib proxy demo. * * @author pdai / @Slf4j public class App {

/**
 * main interface.
 *
 * @param args args
 */
public static void main(String[] args) {
    log.info("Init application context");
    // create and configure beans
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            "tech.pdai.springframework");

    // retrieve configured instance
    User user = (User) context.getBean("user");

    // print info from beans
    log.info(user.toString());

    log.info("Shutdown application context");
    context.registerShutdownHook();
}

} ```

輸出結果(剔除無關輸出):

java 12:44:42.547 [main] INFO tech.pdai.springframework.App - Init application context ... 12:44:43.134 [main] INFO tech.pdai.springframework.processor.MyBeanFactoryPostProcessor - execute BeanFactoryPostProcessor#postProcessBeanFactory ... 12:44:43.216 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user' 12:44:43.216 [main] INFO tech.pdai.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation for user 12:44:43.236 [main] INFO tech.pdai.springframework.entity.User - execute User#new User() 12:44:43.237 [main] INFO tech.pdai.springframework.entity.User - execute User#setName(pdai) 12:44:43.237 [main] INFO tech.pdai.springframework.entity.User - execute User#setAge(18) 12:44:43.237 [main] INFO tech.pdai.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation for user 12:44:43.237 [main] INFO tech.pdai.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessProperties for user 12:44:43.242 [main] INFO tech.pdai.springframework.entity.User - execute BeanNameAware#setBeanName 12:44:43.242 [main] INFO tech.pdai.springframework.entity.User - execute BeanFactoryAware#setBeanFactory 12:44:43.242 [main] INFO tech.pdai.springframework.entity.User - execute ApplicationContextAware#setApplicationContext 12:44:43.242 [main] INFO tech.pdai.springframework.processor.MyBeanPostProcessor - execute BeanPostProcessor#postProcessBeforeInitialization for user 12:44:43.242 [main] INFO tech.pdai.springframework.entity.User - execute InitializingBean#afterPropertiesSet 12:44:43.243 [main] INFO tech.pdai.springframework.entity.User - execute User#doInit 12:44:43.243 [main] INFO tech.pdai.springframework.processor.MyBeanPostProcessor - execute BeanPostProcessor#postProcessAfterInitialization for user 12:44:43.270 [main] INFO tech.pdai.springframework.App - User(name=pdai, age=18) 12:44:43.270 [main] INFO tech.pdai.springframework.App - Shutdown application context 12:44:43.276 [SpringContextShutdownHook] INFO tech.pdai.springframework.entity.User - execute DisposableBean#destroy 12:44:43.276 [SpringContextShutdownHook] INFO tech.pdai.springframework.entity.User - execute User#doDestroy

參考文章

https://juejin.cn/post/6844903843596107790

https://www.zhihu.com/question/438247718/answer/1730527725

更多文章

首先, 從Spring框架的整體架構和組成對整體框架有個認知。

  • Spring基礎 - Spring和Spring框架組成
  • Spring是什麼?它是怎麼誕生的?有哪些主要的組件和核心功能呢? 本文通過這幾個問題幫助你構築Spring和Spring Framework的整體認知。

其次,通過案例引出Spring的核心(IoC和AOP),同時對IoC和AOP進行案例使用分析。

基於Spring框架和IOC,AOP的基礎,為構建上層web應用,需要進一步學習SpringMVC。

  • Spring基礎 - SpringMVC請求流程和案例
  • 前文我們介紹了Spring框架和Spring框架中最為重要的兩個技術點(IOC和AOP),那我們如何更好的構建上層的應用呢(比如web 應用),這便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技術基礎上,遵循上述Web MVC的規範推出的web開發框架,目的是為了簡化Java棧的web開發。 本文主要介紹SpringMVC的請求流程和基礎案例的編寫和運行。

Spring進階 - IoC,AOP以及SpringMVC的源碼分析

  • Spring進階 - Spring IOC實現原理詳解之IOC體系結構設計
  • 在對IoC有了初步的認知後,我們開始對IOC的實現原理進行深入理解。本文將幫助你站在設計者的角度去看IOC最頂層的結構設計
  • Spring進階 - Spring IOC實現原理詳解之IOC初始化流程
  • 上文,我們看了IOC設計要點和設計結構;緊接着這篇,我們可以看下源碼的實現了:Spring如何實現將資源配置(以xml配置為例)通過加載,解析,生成BeanDefination並註冊到IoC容器中的
  • Spring進階 - Spring IOC實現原理詳解之Bean實例化(生命週期,循環依賴等)
  • 上文,我們看了IOC設計要點和設計結構;以及Spring如何實現將資源配置(以xml配置為例)通過加載,解析,生成BeanDefination並註冊到IoC容器中的;容器中存放的是Bean的定義即BeanDefinition放到beanDefinitionMap中,本質上是一個ConcurrentHashMap<String, Object>;並且BeanDefinition接口中包含了這個類的Class信息以及是否是單例等。那麼如何從BeanDefinition中實例化Bean對象呢,這是本文主要研究的內容?
  • Spring進階 - Spring AOP實現原理詳解之切面實現
  • 前文,我們分析了Spring IOC的初始化過程和Bean的生命週期等,而Spring AOP也是基於IOC的Bean加載來實現的。本文主要介紹Spring AOP原理解析的切面實現過程(將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等信息一併封裝到Advisor,為後續交給代理增強實現做準備的過程)。
  • Spring進階 - Spring AOP實現原理詳解之AOP代理
  • 上文我們介紹了Spring AOP原理解析的切面實現過程(將切面類的所有切面方法根據使用的註解生成對應Advice,並將Advice連同切入點匹配器和切面類等信息一併封裝到Advisor)。本文在此基礎上繼續介紹,代理(cglib代理和JDK代理)的實現過程。
  • Spring進階 - Spring AOP實現原理詳解之Cglib代理實現
  • 我們在前文中已經介紹了SpringAOP的切面實現和創建動態代理的過程,那麼動態代理是如何工作的呢?本文主要介紹Cglib動態代理的案例和SpringAOP實現的原理。
  • Spring進階 - Spring AOP實現原理詳解之JDK代理實現
  • 上文我們學習了SpringAOP Cglib動態代理的實現,本文主要是SpringAOP JDK動態代理的案例和實現部分。
  • Spring進階 - SpringMVC實現原理之DispatcherServlet初始化的過程
  • 前文我們有了IOC的源碼基礎以及SpringMVC的基礎,我們便可以進一步深入理解SpringMVC主要實現原理,包含DispatcherServlet的初始化過程和DispatcherServlet處理請求的過程的源碼解析。本文是第一篇:DispatcherServlet的初始化過程的源碼解析。
  • Spring進階 - SpringMVC實現原理之DispatcherServlet處理請求的過程
  • 前文我們有了IOC的源碼基礎以及SpringMVC的基礎,我們便可以進一步深入理解SpringMVC主要實現原理,包含DispatcherServlet的初始化過程和DispatcherServlet處理請求的過程的源碼解析。本文是第二篇:DispatcherServlet處理請求的過程的源碼解析。