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

一文解讀Spring Bean的生命周期

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

1. Spring IOC容器

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

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

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

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í)被銷(xiāo)毀。

而對(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容器初始化和銷(xiāo)毀Bean的過(guò)程,通過(guò)對(duì)它的學(xué)習(xí)就可以知道如何在初始化和銷(xiāo)毀的時(shí)候加入自定義的方法,以滿足特定的需求。如下圖:

從上圖可以看到,Spring IoC容器對(duì)Bean 的管理還是比較復(fù)雜的,Spring loC容器在執(zhí)行了初始化和依賴(lài)注入后,會(huì)執(zhí)行一定的步驟來(lái)完成初始化,通過(guò)這些步驟我們就能自定義初始化,而在Spring IoC 容器正常關(guān)閉的時(shí)候,它也會(huì)執(zhí)行一定的步驟來(lái)關(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)類(lèi),那么才會(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 的銷(xiāo)毀,其步驟如下:

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

1.2.1 BeanDefinition

Spring容器啟動(dòng)的過(guò)程中,會(huì)將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。不管是是通過(guò)xml配置文件的<Bean>標(biāo)簽,還是通過(guò)注解配置的@Bean,還是@Compontent標(biāo)注的類(lèi),還是掃描得到的類(lèi),它最終都會(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類(lèi):表示根bean定義信息,通常bean中沒(méi)有父bean的就使用這種表示。

ChildBeanDefinition類(lèi):表示子bean定義信息,如果需要指定父bean的,可以使用ChildBeanDefinition來(lái)定義子bean的配置信息,里面有parentName屬性,用來(lái)指定父bean的名稱(chēng)。

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

ConfigurationClassBeanDefinition類(lèi):表示通過(guò)配置類(lèi)中@Bean方法定義bean信息

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

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

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

1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor

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

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

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

1.2.3 測(cè)試生命周期

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

自定義@MyAutowired注解

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

定義User實(shí)體類(lèi)

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)來(lái),因此在這一步?jīng)]辦法處理對(duì)象本身,
    // 只能增加一些額外的邏輯。 若要使用它,我們需要讓bean實(shí)現(xiàn)該接口,把要增加的邏輯寫(xiě)在該函數(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)文章

  • spring security獲取用戶信息為null或者串值的解決

    spring security獲取用戶信息為null或者串值的解決

    這篇文章主要介紹了spring security獲取用戶信息為null或者串值的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Spring Bean初始化和銷(xiāo)毀的三種方式

    Spring Bean初始化和銷(xiāo)毀的三種方式

    這篇文章介紹了Spring框架中Bean的初始化和銷(xiāo)毀的幾種方式,包括實(shí)現(xiàn)InitializingBean接口、使用@PostConstruct注解、自定義init方法以及實(shí)現(xiàn)DisposableBean接口、使用@PreDestroy注解和自定義銷(xiāo)毀方法,需要的朋友可以參考下
    2025-11-11
  • Springboot工具類(lèi)StringUtils使用教程

    Springboot工具類(lèi)StringUtils使用教程

    這篇文章主要介紹了Springboot內(nèi)置的工具類(lèi)之StringUtils的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-12-12
  • Java中實(shí)現(xiàn)接口與繼承的區(qū)別及說(shuō)明

    Java中實(shí)現(xiàn)接口與繼承的區(qū)別及說(shuō)明

    這篇文章主要介紹了Java中實(shí)現(xiàn)接口與繼承的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 使用遞歸算法結(jié)合數(shù)據(jù)庫(kù)解析成Java樹(shù)形結(jié)構(gòu)的代碼解析

    使用遞歸算法結(jié)合數(shù)據(jù)庫(kù)解析成Java樹(shù)形結(jié)構(gòu)的代碼解析

    這篇文章主要介紹了使用遞歸算法結(jié)合數(shù)據(jù)庫(kù)解析成Java樹(shù)形結(jié)構(gòu)的代碼解析的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • Java多線程atomic包介紹及使用方法

    Java多線程atomic包介紹及使用方法

    這篇文章主要介紹了Java多線程atomic包介紹及使用方法,涉及原子更新基本類(lèi)型介紹及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • java構(gòu)造器復(fù)用方式

    java構(gòu)造器復(fù)用方式

    這篇文章主要介紹了java構(gòu)造器復(fù)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)之ArrayList從順序表到實(shí)現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)之ArrayList從順序表到實(shí)現(xiàn)

    Java中的ArrayList是一種基于數(shù)組實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu),支持動(dòng)態(tài)擴(kuò)容和隨機(jī)訪問(wèn)元素,可用于實(shí)現(xiàn)順序表等數(shù)據(jù)結(jié)構(gòu)。ArrayList在內(nèi)存中連續(xù)存儲(chǔ)元素,支持快速的隨機(jī)訪問(wèn)和遍歷。通過(guò)學(xué)習(xí)ArrayList的實(shí)現(xiàn)原理和使用方法,可以更好地掌握J(rèn)ava中的數(shù)據(jù)結(jié)構(gòu)和算法
    2023-04-04
  • Java手把手必會(huì)的實(shí)例漢諾塔講解練習(xí)

    Java手把手必會(huì)的實(shí)例漢諾塔講解練習(xí)

    漢諾塔,傳說(shuō)神在創(chuàng)造世界的時(shí)候做了三根金剛石柱子,并在一個(gè)教塔里留下了三根金剛石棒,第一根上面從上到下套著64個(gè)按從小到大排列的金盤(pán),神命令廟里的眾僧將它們一個(gè)個(gè)地從這根金剛石棒搬到另一根金剛石棒上,大盤(pán)不能放在小盤(pán)上。最后64個(gè)金盤(pán)仍然要按從小到大排列
    2021-09-09
  • 淺析Java基于Socket的文件傳輸案例

    淺析Java基于Socket的文件傳輸案例

    這篇文章主要針對(duì)Java基于Socket的文件傳輸案例進(jìn)行詳細(xì)解析,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2016-02-02

最新評(píng)論

宾阳县| 洞头县| 平南县| 资中县| 乌兰察布市| 唐海县| 信阳市| 哈尔滨市| 孟津县| 常熟市| 德庆县| 岚皋县| 宝鸡市| 河池市| 灵丘县| 观塘区| 新邵县| 南乐县| 榕江县| 金溪县| 台南县| 阿巴嘎旗| 株洲市| 英德市| 绥德县| 碌曲县| 运城市| 二连浩特市| 浦北县| 兰溪市| 思南县| 潮安县| 江川县| 民县| 镇沅| 贞丰县| 宣武区| 天祝| 宁津县| 寿宁县| 大姚县|