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

pdai發表於2022-06-29

上文,我們看了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例項。

// 根據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方法進行實現的:

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方法(這個方法很長,我們主要看它的整體思路和設計要點):

// 引數typeCheckOnly:bean例項是否包含一個型別檢查
protected <T> T doGetBean(
			String name, @Nullable Class<T> 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單例模式下的屬性依賴

先來看下這三級快取

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

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

  • 第一層快取(singletonObjects):單例物件快取池,已經例項化並且屬性賦值,這裡的物件是成熟物件
  • 第二層快取(earlySingletonObjects):單例物件快取池,已經例項化但尚未屬性賦值,這裡的物件是半成品物件
  • 第三層快取(singletonFactories): 單例工廠的快取

如下是獲取單例中

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,定義以下:

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

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

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介面:

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的實現類

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

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

定義InstantiationAwareBeanPostProcessor的實現類

/**
 * @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的實現類

/**
 * @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

/**
 * @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;
    }
}

測試的主方法

/**
 * 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();
    }
}

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

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處理請求的過程的原始碼解析。

相關文章