<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      一文搞懂 Spring Bean 的生命周期

      一. 前言

      在學習Spring框架的IOC、AOP兩大功能之前,首先需要了解這兩個技術的基礎——Bean。在Spring框架中,Bean無處不在,IOC容器管理的對象就是各種各樣的Bean。理解Bean的生命周期有助于我們更好的理解和使用Spring框架的IOC功能,也有助于我們理解框架如何初始化、使用和管理Bean。接下來我們通過代碼實現觀察 BeanFactory 與 ApplicationContext 中bean的生命周期。

      二. BeanFactory中Bean的生命周期

      Bean 的生命周期概括起來就是 4 個階段

      1. 實例化(Instantiation)
      2. 屬性賦值(Populate)
      3. 初始化(Initialization)
      4. 銷毀(Destruction)

      在四個階段中,Spring框架會向外暴露多個擴展點,此時業務代碼可以根據情況,從不同的擴展點切入影響Bean的默認創建行為。

      • 其中橙色和綠色的是容器級別生命周期接口,也就是所有的Bean初始化時都會發生作用。主要包含兩個接口InstantiationAwareBeanPostProcessor、BeanPostProcessor,一般被稱為類后處理器。也可根據BeanName進行過濾對指定的Bean進行后處理。
      • 藍色的是Bean級生命周期接口方法,只有實現了這些接口的Bean進行初始化時,才會起作用。包含BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean。
      • 灰色的是Bean自身的方法,通過Bean定義構造函數、setter屬性賦值函數、init-method 和 destroy-method 所指定的方法。

      三.擴展點

      3.1 InstantiationAwareBeanPostProcessor

      InstantiationAwareBeanPostProcessor主要是 Bean 實例化前后的擴展點,通常用于修改特定目標 bean 的默認實例化行為,例如創建具有特殊 TargetSources 的代理(池化目標、延遲初始化目標等),或實現額外的注入策略,如字段注入。

      該接口是一個特殊用途的接口,主要供框架內部使用,建議盡可能實現普通的 BeanPostProcessor 接口。

      public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
      
          /**
      	 * 自身方法,是最先執行的方法,它在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。
      	 * 由于這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。
      	 * 如果該方法的返回值代替原本該生成的目標對象,后續只有postProcessAfterInitialization方法會調用,
      	 * 其它方法不再調用;否則按照正常的流程走
      	 * @param beanClass
      	 * @param beanName
      	 * @return
      	 * @throws BeansException
      	 */
      	@Nullable
      	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
      		return null;
      	}
      
      
          /**
      	 * 在目標對象實例化之后調用,這個時候對象已經被實例化,但是該實例的屬性還未被設置,都是null。
      	 * 因為它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素
      	 * (因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,并且不需要check,
      	 * 那么postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行
      	 */
      	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
      		return true;
      	}
      
          /**
          *對屬性值進行修改,如果postProcessAfterInstantiation方法返回false,
          *該方法可能不會被調用。可以在該方法內對屬性值進行修改
          */
      	@Nullable
      	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
      			throws BeansException {
      
      		return null;
      	}
      
          /**
      	 * 對屬性值進行修改,如果postProcessAfterInstantiation方法返回false,該方法可能不會被調用。可以在該方法內對屬性值進行修改
      	 * 從 5.1 開始,支持 {@link postProcessProperties(PropertyValues, Object, String)}
      	 */
      	@Deprecated
      	@Nullable
      	default PropertyValues postProcessPropertyValues(
      			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
      
      		return pvs;
      	}
      
      

      其中postProcessPropertiespostProcessPropertyValues作用相似,且觸發時機相同,只是在 5.1 版本之后,更建議使用postProcessProperties

      3.2 Aware

      Aware 接口為 Spring 容器的核心接口,是一個具有標識作用的超級接口,實現了該接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回調的方式。

      Aware 接口是一個空接口,實際的方法簽名由各個子接口來確定,且該接口通常只會有一個接收單參數的 set 方法,該 set 方法的命名方式為 set + 去掉接口名中的 Aware 后綴,即 XxxAware 接口,則方法定義為 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。

      Aware 的子接口需要提供一個 setXxx 方法,我們知道 set 是設置屬性值的方法,即 Aware 類接口的 setXxx 方法其實就是設置 xxx 屬性值的。例如ApplicationContextAware

      public interface ApplicationContextAware extends Aware {
      
      	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
      
      }
      

      詳細介紹參考:IoC 之深入分析 Aware 接口?

      3.3 BeanPostProcessor

      BeanPostProcessor也稱為Bean后置處理器,它是Spring中定義的接口,在Spring容器的創建過程中(具體為Bean初始化前后)會回調BeanPostProcessor中定義的兩個方法,接口如下:

      public interface BeanPostProcessor {
      
         /**
          * 初始化前執行的鉤子
          */
         @Nullable
         default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
         }
      
         /**
          * 初始化后,執行的鉤子
          */
         @Nullable
         default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
         }
      
      }
      

      詳細實現原理參考:IoC 之深入分析 ?BeanPostProcessor

      3.4 InitializingBean 和 init-method

      InitializingBean 是一個接口,它為 Spring Bean 的初始化提供了一種方式,它有一個 #afterPropertiesSet() 方法,在 bean 的初始化進程中會判斷當前 bean 是否實現了 InitializingBean,如果實現了則調用 #afterPropertiesSet() 方法,進行初始化工作。然后再檢查是否也指定了 init-method ,如果指定了則通過反射機制調用指定的 init-method 方法。代碼如下:

      public interface InitializingBean {
      	void afterPropertiesSet() throws Exception;
      }
      

      詳細介紹參考:IoC 之深入分析 InitializingBean 和 init-method

      四. 源碼分析

      4.1 bean 實例化

      #doCreateBean(...) 方法中,首先進行 bean 實例化工作,主要由 #createBeanInstance(...) 方法實現,該方法返回一個 BeanWrapper 對象。BeanWrapper 對象是 Spring 的一個低級 Bean 基礎結構的核心接口,為什么說是低級呢?因為這個時候的 Bean 還不能夠被我們使用,連最基本的屬性都沒有設置。而且在我們實際開發過程中,一般都不會直接使用該類,而是通過 BeanFactory 隱式使用。

      BeanWrapper 接口有一個默認實現類 BeanWrapperImpl,其主要作用是對 Bean 進行“包裹”,然后對這個包裹的 bean 進行操作,比如后續注入 bean 屬性。

      在實例化 bean 過程中,Spring 采用“策略模式”來決定采用哪種方式來實例化 bean,一般有反射和 CGLIB 動態字節碼兩種方式。

      InstantiationStrategy 定義了 Bean 實例化策略的抽象接口,其子類 SimpleInstantiationStrategy 提供了基于反射來實例化對象的功能,但是不支持方法注入方式的對象實例化。CglibSubclassingInstantiationStrategy 繼承 SimpleInstantiationStrategy,他除了擁有父類以反射實例化對象的功能外,還提供了通過 CGLIB 的動態字節碼的功能進而支持方法注入所需的對象實例化需求。默認情況下,Spring 采用 CglibSubclassingInstantiationStrategy。

      關于 Bean 實例化的詳細過程,請參考這篇文章:創建Bean的流程

      4.2 激活Aware

      當 Spring 完成 bean 對象實例化并且設置完相關屬性和依賴后,則會開始 bean 的初始化進程( #initializeBean(...) ),初始化第一個階段是檢查當前 bean 對象是否實現了一系列以 Aware 結尾的的接口。

      Aware 接口為 Spring 容器的核心接口,是一個具有標識作用的超級接口,實現了該接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回調的方式。

      在初始化階段主要是感知 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 。代碼如下:

      // AbstractAutowireCapableBeanFactory.java
      
      private void invokeAwareMethods(final String beanName, final Object bean) {
      	if (bean instanceof Aware) {
      	    // BeanNameAware
      		if (bean instanceof BeanNameAware) {
      			((BeanNameAware) bean).setBeanName(beanName);
      		}
      		// BeanClassLoaderAware
      		if (bean instanceof BeanClassLoaderAware) {
      			ClassLoader bcl = getBeanClassLoader();
      			if (bcl != null) {
      				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
      			}
      		}
      		// BeanFactoryAware
      		if (bean instanceof BeanFactoryAware) {
      			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      		}
      	}
      }
      
      • BeanNameAware:對該 bean 對象定義的 beanName 設置到當前對象實例中
      • BeanClassLoaderAware:將當前 bean 對象相應的 ClassLoader 注入到當前對象實例中
      • BeanFactoryAware:BeanFactory 容器會將自身注入到當前對象實例中,這樣當前對象就會擁有一個 BeanFactory 容器的引用。

      當然,Spring 不僅僅只是提供了上面三個 Aware 接口,而是一系列:

      • LoadTimeWeaverAware:加載Spring Bean時織入第三方模塊,如AspectJ
      • BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
      • ResourceLoaderAware:底層訪問資源的加載器
      • PortletConfigAware:PortletConfig
      • PortletContextAware:PortletContext
      • ServletConfigAware:ServletConfig
      • ServletContextAware:ServletContext
      • MessageSourceAware:國際化
      • ApplicationEventPublisherAware:應用事件
      • NotificationPublisherAware:JMX通知

      4.3 BeanPostProcessor

      初始化第二個階段則是 BeanPostProcessor 增強處理,在該階段 BeanPostProcessor 會處理當前容器內所有符合條件的實例化后的 bean 對象。它主要是對 Spring 容器提供的 bean 實例對象進行有效的擴展,允許 Spring 在初始化 bean 階段對其進行定制化修改,如處理標記接口或者為其提供代理實現。

      4.4 InitializingBean 和 init-method

      初始化階段,會先執行InitializingBean接口的afterPropertiesSet方法,再執行自定義Init方法

      // AbstractAutowireCapableBeanFactory.java
      
      protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
      		throws Throwable {
          // 首先會檢查是否是 InitializingBean ,如果是的話需要調用 afterPropertiesSet()
      	boolean isInitializingBean = (bean instanceof InitializingBean);
      	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      		if (logger.isTraceEnabled()) {
      			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      		}
      		if (System.getSecurityManager() != null) { // 安全模式
      			try {
      				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                          // 屬性初始化的處理
      					((InitializingBean) bean).afterPropertiesSet();
      					return null;
      				}, getAccessControlContext());
      			} catch (PrivilegedActionException pae) {
      				throw pae.getException();
      			}
      		} else {
                  // 屬性初始化的處理
      			((InitializingBean) bean).afterPropertiesSet();
      		}
      	}
      
      	if (mbd != null && bean.getClass() != NullBean.class) {
              // 判斷是否指定了 init-method(),
              // 如果指定了 init-method(),則再調用制定的init-method
      		String initMethodName = mbd.getInitMethodName();
      		if (StringUtils.hasLength(initMethodName) &&
      				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
      				!mbd.isExternallyManagedInitMethod(initMethodName)) {
                  // 激活用戶自定義的初始化方法
                  // 利用反射機制執行
      			invokeCustomInitMethod(beanName, bean, mbd);
      		}
      	}
      }
      

      4.5 DisposableBean 和 destroy-method

      與 InitializingBean 和 init-method 用于對象的自定義初始化工作相似,DisposableBean和 destroy-method 則用于對象的自定義銷毀工作。

      當一個 bean 對象經歷了實例化、設置屬性、初始化階段,那么該 bean 對象就可以供容器使用了(調用的過程)。當完成調用后,如果是 singleton 類型的 bean ,則會看當前 bean 是否應實現了 DisposableBean 接口或者配置了 destroy-method 屬性,如果是的話,則會為該實例注冊一個用于對象銷毀的回調方法,便于在這些 singleton 類型的 bean 對象銷毀之前執行銷毀邏輯。

      但是,并不是對象完成調用后就會立刻執行銷毀方法,因為這個時候 Spring 容器還處于運行階段,只有當 Spring 容器關閉的時候才會去調用。但是, Spring 容器不會這么聰明會自動去調用這些銷毀方法,而是需要我們主動去告知 Spring 容器。

      • 對于 BeanFactory 容器而言,我們需要主動調用 #destroySingletons() 方法,通知 BeanFactory 容器去執行相應的銷毀方法。
      • 對于 ApplicationContext 容器而言,調用 #registerShutdownHook() 方法。

      代碼注釋參考:Spring源碼注釋

      五. 測試

      下面用一個實例來真實看看看上面執行的邏輯,畢竟理論是不能缺少實踐的:

      public class LifeCycleBean implements BeanNameAware,BeanFactoryAware,BeanClassLoaderAware,BeanPostProcessor,
              InitializingBean,DisposableBean {
      
          private String test;
      
          public String getTest() {
              return test;
          }
      
          public void setTest(String test) {
              System.out.println("屬性注入....");
              this.test = test;
          }
      
          public LifeCycleBean(){ // 構造方法
              System.out.println("構造函數調用...");
          }
      
          public void display(){
              System.out.println("方法調用...");
          }
      
          @Override
          public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
              System.out.println("BeanFactoryAware 被調用...");
          }
      
          @Override
          public void setBeanName(String name) {
              System.out.println("BeanNameAware 被調用...");
          }
      
          @Override
          public void setBeanClassLoader(ClassLoader classLoader) {
              System.out.println("BeanClassLoaderAware 被調用...");
          }
      
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("BeanPostProcessor postProcessBeforeInitialization 被調用...");
              return bean;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("BeanPostProcessor postProcessAfterInitialization 被調用...");
              return bean;
          }
      
          @Override
          public void destroy() throws Exception {
              System.out.println("DisposableBean destroy 被調動...");
          }
      
          @Override
          public void afterPropertiesSet() throws Exception {
              System.out.println("InitializingBean afterPropertiesSet 被調動...");
          }
      
          public void initMethod(){
              System.out.println("init-method 被調用...");
          }
      
          public void destroyMethdo(){
              System.out.println("destroy-method 被調用...");
          }
      
      }
      
      • LifeCycleBean 繼承了 BeanNameAware , BeanFactoryAware , BeanClassLoaderAware , BeanPostProcessor , InitializingBean , DisposableBean 六個接口,同時定義了一個 test 屬性用于驗證屬性注入和提供一個 #display() 方法用于模擬調用。

      配置如下:

      <bean id="lifeCycle" class="org.springframework.core.test.lifeCycleBean"
              init-method="initMethod" destroy-method="destroyMethdo">
          <property name="test" value="test"/>
      </bean>
      
      • 配置 init-methoddestroy-method

      測試方法如下:

      // BeanFactory 容器一定要調用該方法進行 BeanPostProcessor 注冊
      factory.addBeanPostProcessor(new LifeCycleBean()); // <1>
      
      LifeCycleBean lifeCycleBean = (LifeCycleBean) factory.getBean("lifeCycle");
      lifeCycleBean.display();
      
      System.out.println("方法調用完成,容器開始關閉....");
      // 關閉容器
      factory.destroySingletons();
      

      運行結果:

      構造函數調用...
      構造函數調用...
      屬性注入....
      BeanNameAware 被調用...
      BeanClassLoaderAware 被調用...
      BeanFactoryAware 被調用...
      BeanPostProcessor postProcessBeforeInitialization 被調用...
      InitializingBean afterPropertiesSet 被調動...
      init-method 被調用...
      BeanPostProcessor postProcessAfterInitialization 被調用...
      方法調用...
      方法調用完成,容器開始關閉....
      DisposableBean destroy 被調動...
      destroy-method 被調用...
      

      本文參考至:

      Bean生命周期 | Home page (tru-xu.github.io)

      Spring源碼分析

      posted @ 2022-05-03 17:19  聽到微笑  閱讀(86)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 国产午夜福利在线视频| 中国老太婆video| 日本一区二区三区视频一| 国产中文字幕精品免费 | 国内自拍网红在线综合一区| 国产一区二区三区尤物视频| 饥渴的熟妇张开腿呻吟视频| 国产v综合v亚洲欧美大天堂| 成人午夜福利视频后入| 国产国产人免费人成免费| 亚洲男人第一无码av网站| 亚洲欧洲精品日韩av| 国产精品综合一区二区三区| 亚洲午夜无码久久久久蜜臀AV| 欧美人与动牲交a免费| 免费人成网上在线观看网址| 色欲狠狠躁天天躁无码中文字幕 | 一区二区和激情视频| 日韩人妻少妇一区二区三区| 久久av色欲av久久蜜桃网| 国产一区二区三区色噜噜| 中国熟妇牲交视频| 免费十八禁一区二区三区| 国产日韩av二区三区| 99久久国产成人免费网站| 亚洲熟少妇一区二区三区| 狠狠色综合播放一区二区| 夜色资源站www国产在线视频 | 夜爽8888视频在线观看| 国产精品无码v在线观看| 亚洲第一综合天堂另类专| 国产精品亚洲二区在线播放| 国产精品一在线观看| 日韩精品中文字幕国产一| 三级国产在线观看| 国产精品自拍自在线播放| 阳信县| 2019亚洲午夜无码天堂| 日本在线a一区视频高清视频| 国语自产拍精品香蕉在线播放| 九九热视频在线观看精品|