最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Bean 中的生命周期和獲取方式詳解

 更新時間:2024年12月07日 10:46:22   作者:程序猿進階  
Bean的加載和獲取過程涉及配置文件解析、資源加載、XML解析和BeanDefinition注冊等步驟,本文給大家介紹Spring Bean 的生命周期和獲取方式,感興趣的朋友跟隨小編一起看看吧

一、Spring Bean 的生命周期,如何被管理的

對于普通的 Java對象,當 new的時候創(chuàng)建對象,當它沒有任何引用的時候被垃圾回收機制回收。而由 Spring IoC容器托管的對象,它們的生命周期完全由容器控制。Spring 中每個 Bean的生命周期如下:

主要對幾個重要的步驟進行說明:
【1】實例化 Bean: 對于 BeanFactory容器,當客戶向容器請求一個尚未初始化的 bean時,或初始化 bean的時候需要注入另一個尚未初始化的依賴時,容器就會調(diào)用 createBean進行實例化。對于 ApplicationContext容器,當容器啟動結(jié)束后,便實例化所有的單實例 bean。容器通過獲取 BeanDefinition對象中的信息進行實例化。并且這一步僅僅是簡單的實例化,并未進行依賴注入。實例化對象被包裝在 BeanWrapper 對象中,BeanWrapper 提供了設置對象屬性的接口,從而避免了使用反射機制設置屬性。通過工廠方法或者執(zhí)行構(gòu)造器解析執(zhí)行即可:創(chuàng)建的對象是個空對象。
【2】設置對象屬性(依賴注入): 實例化后的對象被封裝在 BeanWrapper對象中,并且此時對象仍然是一個原生的狀態(tài),并沒有進行依賴注入。緊接著獲取所有的屬性信息通過 populateBean(beanName,mbd,bw,pvs),Spring 根據(jù) BeanDefinition 中的信息進行依賴注入。并且通過 BeanWrapper提供的設置屬性的接口完成依賴注入。賦值之前獲取所有的 InstantiationAwareBeanPostProcessor 后置處理器的 postProcessAfterInstantiation() 第二次獲取InstantiationAwareBeanPostProcessor 后置處理器;執(zhí)行 postProcessPropertyValues()最后為應用 Bean屬性賦值:為屬性利用 setter 方法進行賦值 applyPropertyValues(beanName,mbd,bw,pvs)。
【3】bean 初始化: initializeBean(beanName,bean,mbd)。
 1)執(zhí)行xxxAware 接口的方法,調(diào)用實現(xiàn)了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口的方法。
 2)執(zhí)行后置處理器之前的方法:applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)所有后置處理器的 BeanPostProcessor.postProcessBeforeInitialization()。
 3)執(zhí)行初始化方法: InitializingBean 與 init-methodinvoke 當 BeanPostProcessor的前置處理完成后就會進入本階段。先判斷是否實現(xiàn)了 InitializingBean接口的實現(xiàn);執(zhí)行接口規(guī)定的初始化。其次自定義初始化方法。

InitializingBean 接口只有一個函數(shù):afterPropertiesSet()這一階段也可以在 bean正式構(gòu)造完成前增加我們自定義的邏輯,但它與前置處理不同,由于該函數(shù)并不會把當前 bean對象傳進來,因此在這一步?jīng)]辦法處理對象本身,只能增加一些額外的邏輯。若要使用它,我們需要讓 bean實現(xiàn)該接口,并把要增加的邏輯寫在該函數(shù)中。然后 Spring會在前置處理完成后檢測當前 bean是否實現(xiàn)了該接口,并執(zhí)行 afterPropertiesSet函數(shù)。當然,Spring 為了降低對客戶代碼的侵入性,給 bean的配置提供了 init-method屬性,該屬性指定了在這一階段需要執(zhí)行的函數(shù)名。Spring 便會在初始化階段執(zhí)行我們設置的函數(shù)。init-method 本質(zhì)上仍然使用了InitializingBean接口。
 4)applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);執(zhí)行初始化之后的后置處理器的方法。BeanPostProcessor.postProcessAfterInitialization(result, beanName);
【4】Bean的銷毀: DisposableBean 和 destroy-method:和 init-method 一樣,通過給 destroy-method 指定函數(shù),就可以在bean 銷毀前執(zhí)行指定的邏輯。

Bean 的管理就是通過 IOC容器中的 BeanDefinition信息進行管理的。

二、Spring Bean 的加載和獲取過程

Bean 的加載過程,主要是對配置文件的解析,并注冊 bean 的過程 。

【1】根據(jù)注解或者 XML中 定義 Bean 的基本信息。例如:spring-core.xml

<bean id="myBean" class="com.taobao.pojo"></bean>

【2】獲取配置文件:這里使用最原始的方式獲取。

Resource resource = new ClassPathResource("spring-core.xml")

【3】 利用 XmlBeanFactory 解析并注冊 bean 定義:已經(jīng)完成將配置文件包裝成了 Spring 定義的資源,并觸發(fā)解析和注冊。XmlBeanFactory 實際上是對 DefaultListableBeanFactory(非常核心的類,它包含了基本 IOC 容器所具有的重要功能,是一個 IOC 容器的基本實現(xiàn)。然后是調(diào)用了this.reader.loadBeanDefinitions(resource),從這里開始加載配置文件) 和 XmlBeanDefinitionReader 組合使用方式的封裝,所以這里我們?nèi)匀粚⒗^續(xù)分析基于 XmlBeanFactory 加載 bean 的過程。

XmlBeanFactory beanFactory = new XmlBeanFactory(resource);

Spring 使用了專門的資源加載器對資源進行加載,這里的 reader 就是 XmlBeanDefinitionReader 對象,專門用來加載基于 XML 文件配置的 bean。這里的加載過程為:

①、利用 EncodedResource 二次包裝資源文件;
②、獲取資源輸入流,并構(gòu)造 InputSource 對象:

// 獲取資源的輸入流
InputStream inputStream = encodedResource.getResource().getInputStream();
// 構(gòu)造InputSource對象
InputSource inputSource = new InputSource(inputStream);
// 真正開始從 XML文件中加載 Bean定義
return this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());

這里的 this.doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 就是真正開始加載 XMl 的入口,該方法源碼如下:第一步獲取 org.w3c.dom.Document 對象,第二步由該對象解析得到 BeanDefinition 對象,并注冊到 IOC 容器中。

protected intdoLoadBeanDefinitions(InputSource inputSource, Resource resource){
  try {
    // 1. 加載xml文件,獲取到對應的Document(包含獲取xml文件的實體解析器和驗證模式)
    Document doc = this.doLoadDocument(inputSource, resource);
    // 2. 解析Document對象,并注冊bean
    return this.registerBeanDefinitions(doc, resource);
  } 
}

③、獲取 XML 文件的實體解析器和驗證模式:this.doLoadDocument(inputSource, resource) 包含了獲取實體解析器、驗證模式,以及 Document 對象的邏輯,XML 是半結(jié)構(gòu)化數(shù)據(jù),XML 的驗證模式用于保證結(jié)構(gòu)的正確性,常見的驗證模式有 DTD 和 XSD 兩種。
④、加載 XML 文件,獲取對應的 Document 對象和驗證模式與解析器,解析器就可以加載 Document 對象了,這里本質(zhì)上調(diào)用的是 DefaultDocumentLoader 的 loadDocument() 方法,源碼如下:整個過程類似于我們平常解析 XML 文件的流程。

public DocumentloadDocument(InputSource inputSource, EntityResolver entityResolver,
               ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
    DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource);
}

⑤、由 Document 對象解析并注冊 bean:完成了對 XML 文件的到 Document 對象的解析,我們終于可以解析 Document 對象,并注冊 bean 了,這一過程發(fā)生在 this.registerBeanDefinitions(doc, resource) 中,源碼如下:

public intregisterBeanDefinitions(Document doc, Resource resource)throwsBeanDefinitionStoreException{
    // 使用DefaultBeanDefinitionDocumentReader構(gòu)造
    BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
    // 記錄之前已經(jīng)注冊的BeanDefinition個數(shù)
    int countBefore = this.getRegistry().getBeanDefinitionCount();
    // 加載并注冊bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 返回本次加載的bean的數(shù)量
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

這里方法的作用是創(chuàng)建對應的 BeanDefinitionDocumentReader,并計算返回了過程中新注冊的 bean 的數(shù)量,而具體的注冊過程,則是由 BeanDefinitionDocumentReader 來完成的,具體的實現(xiàn)位于子類 DefaultBeanDefinitionDocumentReader 中:

publicvoidregisterBeanDefinitions(Document doc, XmlReaderContext readerContext){
    this.readerContext = readerContext;
    // 獲取文檔的root結(jié)點
    Element root = doc.getDocumentElement();
    this.doRegisterBeanDefinitions(root);
}

還是按照 Spring 命名習慣,doRegisterBeanDefinitions 才是真正干活的地方,這也是真正開始解析配置的核心所在:

protectedvoiddoRegisterBeanDefinitions(Element root){
  BeanDefinitionParserDelegate parent = this.delegate;
  this.delegate = this.createDelegate(getReaderContext(), root, parent);
    // 處理profile標簽(其作用類比pom.xml中的profile)
    String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    // 解析預處理,留給子類實現(xiàn)
    this.preProcessXml(root);
    // 解析并注冊BeanDefinition
    this.parseBeanDefinitions(root, this.delegate);
    // 解析后處理,留給子類實現(xiàn)
    this.postProcessXml(root);
}

方法在解析并注冊 BeanDefinition 前后各設置一個模板方法,留給子類擴展實現(xiàn),而在this.parseBeanDefinitions(root, this.delegate)中執(zhí)行解析和注冊邏輯:方法中判斷當前標簽是默認標簽還是自定義標簽,并按照不同的策略去解析。

protectedvoidparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate){
    if (delegate.isDefaultNamespace(root)) {
        // 解析默認標簽
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                  // 解析默認標簽
                  this.parseDefaultElement(ele, delegate);
                } else {
                  // 解析自定義標簽
                  delegate.parseCustomElement(ele);
                }
            }
        }
      } else {
        // 解析自定義標簽
        delegate.parseCustomElement(root);
   }
}

到這里我們已經(jīng)完成了靜態(tài)配置到動態(tài) BeanDefinition 的解析,這個時候 bean 的定義已經(jīng)處于內(nèi)存中。

【4】 從 IOC容器加載獲取 bean:我們可以調(diào)用 beanFactory.getBean("myBean") 方法來獲取目標對象。

MyBean myBean = (MyBean) beanFactory.getBean("myBean");

到此這篇關于Spring Bean 的生命周期和獲取方式詳解的文章就介紹到這了,更多相關Spring Bean 生命周期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot基于Actuator遠程關閉服務

    SpringBoot基于Actuator遠程關閉服務

    這篇文章主要介紹了SpringBoot基于Actuator遠程關閉服務,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互實例代碼

    Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互實例代碼

    Axios作為一個流行的前端?HTTP?通信庫,可以極大地簡化前端與后端之間的數(shù)據(jù)交互,這篇文章主要介紹了Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • SpringMVC 單文件,多文件上傳實現(xiàn)詳解

    SpringMVC 單文件,多文件上傳實現(xiàn)詳解

    這篇文章主要介紹了SpringMVC 單文件,多文件上傳實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Java SPI機制原理及代碼實例

    Java SPI機制原理及代碼實例

    這篇文章主要介紹了Java SPI機制原理及代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • 排序算法圖解之Java冒泡排序及優(yōu)化

    排序算法圖解之Java冒泡排序及優(yōu)化

    冒泡排序即通過對待排序的序列從前往后,依次比較相鄰元素的值,若發(fā)現(xiàn)逆序則交換位置,使較大的元素逐漸移動到后部。本文通過圖片和示例介紹了冒泡排序的實現(xiàn)及優(yōu)化,需要的可以參考一下
    2022-11-11
  • SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置指南

    SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置指南

    這篇文章主要給大家介紹了關于SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置的相關資料,在Java SpringBoot項目中如果使用了Mybatis框架,默認情況下執(zhí)行的所有SQL操作都不會打印日志,需要的朋友可以參考下
    2023-10-10
  • jsp如何獲取Session中的值

    jsp如何獲取Session中的值

    這篇文章主要介紹了jsp如何獲取Session中的值,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • java編譯器的基礎知識點

    java編譯器的基礎知識點

    在本篇文章里小編給大家整理的是一篇關于java編譯器的基礎知識點內(nèi)容,有興趣的朋友們可以閱讀下。
    2020-02-02
  • springboot2.1.3配置sftp自定義sftp連接池的詳細過程

    springboot2.1.3配置sftp自定義sftp連接池的詳細過程

    這篇文章主要介紹了springboot2.1.3配置sftp自定義sftp連接池的詳細過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • Spring AI集成DeepSeek三步搞定Java智能應用的詳細過程

    Spring AI集成DeepSeek三步搞定Java智能應用的詳細過程

    本文介紹了如何使用SpringAI集成DeepSeek,一個國內(nèi)頂尖的多模態(tài)大模型,SpringAI提供了一套統(tǒng)一的接口,簡化了與不同AI模型的集成,通過配置文件和簡單的接口調(diào)用,開發(fā)者可以方便地使用DeepSeek進行數(shù)學推理、代碼生成等任務,感興趣的朋友一起看看吧
    2025-03-03

最新評論

延安市| 健康| 泰州市| 静宁县| 广灵县| 曲水县| 凤庆县| 烟台市| 屯门区| 安庆市| 临沭县| 额尔古纳市| 大荔县| 东乌珠穆沁旗| 临夏市| 阳春市| 通州市| 靖安县| 两当县| 比如县| 独山县| 陵川县| 喀喇| 内乡县| 千阳县| 克什克腾旗| 德江县| 察雅县| 安阳县| 水城县| 南阳市| 贵港市| 嘉黎县| 牡丹江市| 盐边县| 淳安县| 襄樊市| 上饶市| 隆德县| 乐陵市| 威远县|