亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文解讀Spring Bean的生命周期

 更新時(shí)間:2023年07月02日 10:16:20   作者:山河亦問安  
這篇文章主要給大家詳細(xì)解讀Spring Bean的生命周期,文中有詳細(xì)的代碼示例,對(duì)我們學(xué)習(xí)Spring Bean的生命周期有一定的幫助,感興趣的同學(xué)跟著小編一起來學(xué)習(xí)吧

1. Spring IOC容器

1.1 Spring IOC 容器的設(shè)計(jì)

Spring IOC 容器的設(shè)計(jì)主要是基于BeanFactoryApplicationContext兩個(gè)接口,其中ApplicationContext是BeanFactory的子接口之一,換句話說BeanFactory是Spring IOC容器所定義的最頂層接口,而ApplicationContext是其高級(jí)接口之一,并且對(duì)于BeanFactory功能做了許多有用的擴(kuò)展,所以在絕大部分的工作場(chǎng)景中,都會(huì)使用ApplicationContext作為Spring IOC 容器,如下圖所示:

首先我們定義一個(gè)User實(shí)體類:

public class User {
    String username;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
}

1.1.1 BeanFactory

BeanFactory的使用注冊(cè)Bean對(duì)象以及獲取Bean對(duì)象代碼如下:

DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
        RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(User.class);
        beanFactory.registerBeanDefinition("user",rootBeanDefinition);
        System.out.println(beanFactory.getBean("user",User.class));

1.1.2 ApplicationContext

ApplicationContext的使用注冊(cè)Bean對(duì)象以及獲取Bean對(duì)象代碼如下:

 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(User.class);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("user", User.class));

1.2 Spring Bean的生命周期

Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能夠精確地知道該 Bean 何時(shí)被創(chuàng)建,何時(shí)初始化完成,以及何時(shí)被銷毀。

而對(duì)于 prototype 作用域的 Bean,Spring 只負(fù)責(zé)創(chuàng)建,當(dāng)容器創(chuàng)建了 Bean 的實(shí)例后,Bean 的實(shí)例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期。每次客戶端請(qǐng)求 prototype 作用域的 Bean 時(shí),Spring 容器都會(huì)創(chuàng)建一個(gè)新的實(shí)例,并且不會(huì)管那些被配置成 prototype 作用域的 Bean 的生命周期。

生命周期主要是為了了解Spring IOC容器初始化和銷毀Bean的過程,通過對(duì)它的學(xué)習(xí)就可以知道如何在初始化和銷毀的時(shí)候加入自定義的方法,以滿足特定的需求。如下圖:

從上圖可以看到,Spring IoC容器對(duì)Bean 的管理還是比較復(fù)雜的,Spring loC容器在執(zhí)行了初始化和依賴注入后,會(huì)執(zhí)行一定的步驟來完成初始化,通過這些步驟我們就能自定義初始化,而在Spring IoC 容器正常關(guān)閉的時(shí)候,它也會(huì)執(zhí)行一定的步驟來關(guān)閉容器,釋放資源。除需要了解整個(gè)生命周期的步驟外,還要知道這些生命周期的接口是針對(duì)什么而言的,首先介紹生命周期的步驟。

1. 如果 Bean 實(shí)現(xiàn)了接口 BeanNameAware的setBeanName方法,那么它就會(huì)調(diào)用這個(gè)方法。
2. 如果 Bean 實(shí)現(xiàn)了接口 BeanFactoryAware 的 setBeanFactory方法,那么它就會(huì)調(diào)用這個(gè)方法。
3. 如果 Bean實(shí)現(xiàn)了接口 ApplicationContextAware 的 setApplicationContext方法,且
Spring loC容器也必須是一個(gè)ApplicationContext 接口的實(shí)現(xiàn)類,那么才會(huì)調(diào)用這個(gè)方法,否則是不調(diào)用的。
4. 如果 Bean 實(shí)現(xiàn)了接口 BeanPostProcessor 的 postProcessBeforeInitialization方法,那么它就會(huì)調(diào)用這個(gè)方法。

5 .如果 Bean實(shí)現(xiàn)了接口BeanFactoryPostProcessor的afterPropertiesSet方法,那么它就會(huì)調(diào)用這個(gè)方法。
6. 如果 Bean自定義了初始化方法,它就會(huì)調(diào)用已定義的初始化方法。
7. 如果Bean 實(shí)現(xiàn)了接口 BeanPostProcessor 的postProcessAfterInitialization方法,完成了這些調(diào)用,這個(gè)時(shí)候Bean 就完成了初始化,那么 Bean就生存在Spring loC的容器中了,使用者就可以從中獲取 Bean的服務(wù)。
8. 當(dāng)服務(wù)器正常關(guān)閉,或者遇到其他關(guān)閉 Spring loC 容器的事件,它就會(huì)調(diào)用對(duì)應(yīng)的方完成Bean 的銷毀,其步驟如下:

如果Bean實(shí)現(xiàn)了接口 DisposableBean 的 destroy方法,那么就會(huì)調(diào)用它。
如果定義了自定義的銷毀方法,那么就會(huì)調(diào)用它。

1.2.1 BeanDefinition

Spring容器啟動(dòng)的過程中,會(huì)將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。不管是是通過xml配置文件的<Bean>標(biāo)簽,還是通過注解配置的@Bean,還是@Compontent標(biāo)注的類,還是掃描得到的類,它最終都會(huì)被解析成一個(gè)BeanDefinition對(duì)象,最后我們的Bean工廠就會(huì)根據(jù)這份Bean的定義信息,對(duì)bean進(jìn)行實(shí)例化、初始化等等操作。

你可以把BeanDefinition丟給Bean工廠,然后Bean工廠就會(huì)根據(jù)這個(gè)信息幫你生產(chǎn)一個(gè)Bean實(shí)例,拿去使用。

BeanDefinition里面里面包含了bean定義的各種信息,如:bean對(duì)應(yīng)的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候選對(duì)象)、primary(是否是主要的候選者)等信息。

RootBeanDefinition類:表示根bean定義信息,通常bean中沒有父bean的就使用這種表示。

ChildBeanDefinition類:表示子bean定義信息,如果需要指定父bean的,可以使用ChildBeanDefinition來定義子bean的配置信息,里面有parentName屬性,用來指定父bean的名稱。

GenericBeanDefinition類:通用的bean定義信息,既可以表示沒有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,這個(gè)類里面也有parentName屬性,用來指定父bean的名稱。

ConfigurationClassBeanDefinition類:表示通過配置類中@Bean方法定義bean信息

可以通過配置類中使用@Bean來標(biāo)注一些方法,通過這些方法來定義bean,這些方法配置的bean信息最后會(huì)轉(zhuǎn)換為ConfigurationClassBeanDefinition類型的對(duì)象。

AnnotatedBeanDefinition接口:表示通過注解的方式定義的bean信息。

BeanDefinitionBuilder:構(gòu)建BeanDefinition的工具類

1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor

InstantiationAwareBeanPostProcessor實(shí)際上繼承了BeanPostProcessor接口。InstantiationAwareBeanPostProcessor作用于實(shí)例化階段的前后,BeanPostProcessor作用于初始化階段的前后。如下圖:

BeanPostProcessor是一個(gè)接口,還有很多子接口,這些接口中提供了很多方法,spring在bean生命周期的不同階段,會(huì)調(diào)用BeanPostProcessor中的一些方法,來對(duì)生命周期進(jìn)行擴(kuò)展,bean生命周期中的所有擴(kuò)展點(diǎn)都是依靠這個(gè)集合中的BeanPostProcessor來實(shí)現(xiàn)的。該接口提供了兩個(gè)函數(shù):postProcessBeforeInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對(duì)象會(huì)被傳遞進(jìn)來,我們就可以對(duì)這個(gè)bean作任何處理。 這個(gè)函數(shù)會(huì)先于InitialzationBean執(zhí)行,因此稱為前置處理。 所有Aware接口的注入就是在這一步完成的。postProcessAfterInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對(duì)象會(huì)被傳遞進(jìn)來,我們就可以對(duì)這個(gè)bean作任何處理。 這個(gè)函數(shù)會(huì)在InitialzationBean完成后執(zhí)行,因此稱為后置處理。

Spring Aware是Spring定義的回調(diào)接口。何為回調(diào)?就是客戶程序C調(diào)用服務(wù)程序S中的某個(gè)函數(shù)A,然后S又在某個(gè)時(shí)候反過來調(diào)用C中的某個(gè)函數(shù)B,對(duì)于C來說,這個(gè)B便叫做回調(diào)函數(shù)。

1.2.3 測(cè)試生命周期

我們自定義一個(gè)User實(shí)體類,要求Spring容器使用我們自定義的@MyAutowired注解標(biāo)注的構(gòu)造方法進(jìn)行構(gòu)造Bean對(duì)象,然后我們觀察在Bean周期的日志打印,更好的理解Bean周期過程。

自定義@MyAutowired注解

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.CONSTRUCTOR)
public @interface MyAutowired {
}

定義User實(shí)體類

public class User implements InitializingBean, DisposableBean {
    String username;
    //Spring為了降低對(duì)客戶代碼的侵入性,給bean的配置提供了init-method屬性,
    // 該屬性指定了在這一階段需要執(zhí)行的函數(shù)名。Spring便會(huì)在初始化階段執(zhí)行我們?cè)O(shè)置的函數(shù)。
    // init-method本質(zhì)上仍然使用了InitializingBean接口。
    public void init(){
        System.out.println(this.getClass().getSimpleName()+" 執(zhí)行自定義初始化方法");
    }
    public User() {
    }
    @MyAutowired
    public User(String username) {
        this.username = username;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("調(diào)用DisposableBean接口的destroy方法");
    }
    //afterPropertiesSet()這一階段也可以在bean正式構(gòu)造完成前增加我們自定義的邏輯,
    // 但它與前置處理不同,由于該函數(shù)并不會(huì)把當(dāng)前bean對(duì)象傳進(jìn)來,因此在這一步?jīng)]辦法處理對(duì)象本身,
    // 只能增加一些額外的邏輯。 若要使用它,我們需要讓bean實(shí)現(xiàn)該接口,把要增加的邏輯寫在該函數(shù)中。
    // 然后Spring會(huì)在前置處理完成后檢測(cè)當(dāng)前bean是否實(shí)現(xiàn)了該接口,并執(zhí)行afterPropertiesSet函數(shù)
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("調(diào)用afterPropertiesSet方法");
    }
}

測(cè)試代碼

public class MyTest {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
        //InstantiationAwareBeanPostProcessor接口在Bean對(duì)象實(shí)例化前的方法
        beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
            public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
                if(beanName.equals("user"))
                System.out.println(beanName+" Bean對(duì)象在實(shí)例化之前操作**");
                return null;
            }
        });
        //InstantiationAwareBeanPostProcessor接口在Bean對(duì)象實(shí)例化后的方法
        beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
            public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
                if(beanName.equals("user"))
                System.out.println(beanName+" Bean對(duì)象在實(shí)例化之后操作**");
                return false;
            }
        });
        //使用自己自定義含有@MyAutowired注解的構(gòu)造方法,實(shí)例化Bean對(duì)象
        beanFactory.addBeanPostProcessor(new SmartInstantiationAwareBeanPostProcessor() {
            public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
                if(beanName.equals("user"))
                System.out.println("實(shí)例化Bean對(duì)象");
                Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
                List<Constructor<?>> collect = Arrays.stream(declaredConstructors).filter(i -> i.isAnnotationPresent(MyAutowired.class)).collect(Collectors.toList());
                Constructor[] constructors = collect.toArray(new Constructor[collect.size()]);
                return constructors.length>0?constructors:null;
            }
        });
        //BeanPostProcessor接口在Bean對(duì)象初始化之前的方法調(diào)用
        beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                if(beanName.equals("user"))
                    System.out.println(beanName+" Bean對(duì)象在初始化之前操作**");
                return null;
            }
        });
       //BeanPostProcessor接口在Bean對(duì)象初始化之后的方法調(diào)用
        beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if(beanName.equals("user"))
                    System.out.println(beanName+" Bean對(duì)象在初始化之后操作**");
                return null;
            }
        });
        RootBeanDefinition rootBeanDefinition= (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(User.class).setInitMethodName("init").getBeanDefinition();
        beanFactory.registerBeanDefinition("user",rootBeanDefinition);
        beanFactory.registerBeanDefinition("username", BeanDefinitionBuilder.genericBeanDefinition(String.class)
                .addConstructorArgValue("admin").getBeanDefinition());
        System.out.println(beanFactory.getBean("user",User.class));
        beanFactory.destroySingletons();
    }
}

測(cè)試截圖

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

相關(guān)文章

  • Java 中運(yùn)行字符串表達(dá)式的方法

    Java 中運(yùn)行字符串表達(dá)式的方法

    這篇文章主要介紹了Java 中運(yùn)行字符串表達(dá)式的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • java web用servlet監(jiān)聽器實(shí)現(xiàn)顯示在線人數(shù)

    java web用servlet監(jiān)聽器實(shí)現(xiàn)顯示在線人數(shù)

    這篇文章主要為大家詳細(xì)介紹了java web用servlet監(jiān)聽器實(shí)現(xiàn)顯示在線人數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • JavaSE程序邏輯控制實(shí)現(xiàn)詳細(xì)圖文教程

    JavaSE程序邏輯控制實(shí)現(xiàn)詳細(xì)圖文教程

    JavaSE是為了開發(fā)桌面應(yīng)用程序和控制臺(tái)應(yīng)用程序而設(shè)計(jì)的,使用JavaSE可以編寫?yīng)毩⑦\(yùn)行的Java應(yīng)用程序,這篇文章主要給大家介紹了關(guān)于JavaSE程序邏輯控制實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • 詳解如何配置springboot跳轉(zhuǎn)html頁面

    詳解如何配置springboot跳轉(zhuǎn)html頁面

    這篇文章主要介紹了詳解如何配置springboot跳轉(zhuǎn)html頁面,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java 數(shù)據(jù)庫連接池c3p0 介紹

    Java 數(shù)據(jù)庫連接池c3p0 介紹

    這篇文章主要介給大家分享了 Java 數(shù)據(jù)庫連接池c3p0 介紹,c3p0 是一個(gè)成熟的、高并發(fā)的 JDBC 連接池庫,支持緩存和 PreparedStatements 的重用。它以LGPL v.2.1或EPL v.1.0授權(quán),下面我們就一起來看看文章內(nèi)容的詳細(xì)介紹吧,需要的朋友也可以參考一下
    2021-11-11
  • Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用詳細(xì)介紹(1)

    Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用詳細(xì)介紹(1)

    這篇文章主要介紹了Mybatis中SqlMapper配置的擴(kuò)展與應(yīng)用(1)的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • Springboot Session共享實(shí)現(xiàn)原理及代碼實(shí)例

    Springboot Session共享實(shí)現(xiàn)原理及代碼實(shí)例

    這篇文章主要介紹了Springboot Session共享實(shí)現(xiàn)原理及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java自定義比較器實(shí)現(xiàn)中文排序

    Java自定義比較器實(shí)現(xiàn)中文排序

    這篇文章主要介紹了Java自定義比較器實(shí)現(xiàn)中文排序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • java讀取解析xml文件實(shí)例

    java讀取解析xml文件實(shí)例

    這篇文章主要介紹了java讀取解析xml文件實(shí)例,本文創(chuàng)建了一個(gè)XML解析類同時(shí)講解了循環(huán)節(jié)點(diǎn)輸出方式,需要的朋友可以參考下
    2015-03-03
  • java根據(jù)負(fù)載自動(dòng)抓取jstack?dump詳情

    java根據(jù)負(fù)載自動(dòng)抓取jstack?dump詳情

    這篇文章主要介紹了java根據(jù)負(fù)載自動(dòng)抓取jstack?dump詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09

最新評(píng)論