欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Bean的管理與SpringBoot自動(dòng)裝配原理解讀

 更新時(shí)間:2024年11月04日 16:11:24   作者:薛定諤的鹽.  
在SpringBoot項(xiàng)目中,啟動(dòng)時(shí)自動(dòng)創(chuàng)建IOC容器并初始化bean對象,支持通過依賴注入獲取,Bean可以通過name或類型獲取,支持單例和非單例等多種作用域,對于第三方Bean,推薦在配置類中用@Bean標(biāo)識方法進(jìn)行定義

1、Bean管理

默認(rèn)情況下,SpringBoot項(xiàng)目在啟動(dòng)的時(shí)候會(huì)自動(dòng)的創(chuàng)建IOC容器,并且在啟動(dòng)的過程當(dāng)中會(huì)自動(dòng)的將bean對象都創(chuàng)建好,存放在IOC容器當(dāng)中。

應(yīng)用程序在運(yùn)行時(shí)需要依賴什么bean對象,就直接進(jìn)行依賴注入就可以了。

1.1 獲取Bean

要想主動(dòng)從IOC容器中獲取到bean對象,需要先拿到IOC容器

想獲取到IOC容器,直接將IOC容器對象注入進(jìn)來就可以了

@Autowired
private ApplicationContext applicationContext; //IOC容器對象

在IOC容器中提供了一些方法,可以主動(dòng)從IOC容器中獲取到bean對象,

介紹3種常用方式:

1.根據(jù)name獲取bean

Object getBean(String name)

2.根據(jù)類型獲取bean

<T> T getBean(Class<T> requiredType)

3.根據(jù)name獲取bean(帶類型轉(zhuǎn)換)

&lt;T&gt; T getBean(String name, Class&lt;T&gt; requiredType)
@SpringBootTest
class SpringbootTheoryApplicationTests {

    @Autowired
    private ApplicationContext applicationContext; //IOC容器對象

    //獲取bean對象
    @Test
    public void testGetBean(){
        //根據(jù)bean的名稱獲取
        MyController bean1 = (MyController) applicationContext.getBean("myController");
        System.out.println(bean1);

        //根據(jù)bean的類型獲取
        MyController bean2 = applicationContext.getBean(MyController.class);
        System.out.println(bean2);

        //根據(jù)bean的名稱 及 類型獲取
        MyController bean3 = applicationContext.getBean("myController", MyController.class);
        System.out.println(bean3);
    }

}

運(yùn)行結(jié)果:

com.wbr.controller.MyController@2fa47368

com.wbr.controller.MyController@2fa47368

com.wbr.controller.MyController@2fa47368

可以看到三個(gè)bean的打印結(jié)果都是一樣的,說明IOC容器當(dāng)中的bean對象只有一個(gè)。

默認(rèn)情況下,IOC中的bean對象是單例

1.2 Bean的作用域

IOC容器中,默認(rèn)bean對象是單例模式(只有一個(gè)實(shí)例對象)。

想要設(shè)置bean對象為非單例就需要設(shè)置bean的作用域。

在Spring中支持五種作用域,后三種在web環(huán)境才生效:

作用域說明
singleton容器內(nèi)同名稱的bean只有一個(gè)實(shí)例(單例)(默認(rèn))
prototype每次使用該bean時(shí)會(huì)創(chuàng)建新的實(shí)例(非單例)
request每個(gè)請求范圍內(nèi)會(huì)創(chuàng)建新的實(shí)例
session每個(gè)會(huì)話范圍內(nèi)會(huì)創(chuàng)建新的實(shí)例
application每個(gè)應(yīng)用范圍內(nèi)會(huì)創(chuàng)建新的實(shí)例

可以借助Spring中的@Scope注解來進(jìn)行配置作用域

測試一:

Controller類

//當(dāng)我們未加@Scope注解時(shí),默認(rèn)bean的作用域?yàn)椋篅Scope("singleton") (單例模式)
@Lazy //延遲加載(第一次使用bean對象時(shí),才會(huì)創(chuàng)建bean對象并交給ioc容器管理)
@RestController
public class MyController {

    @Autowired
    private MyService myService;

    public MyController(){
        System.out.println("MyController 構(gòu)造方法執(zhí)行了...");
    }
}

測試類

@SpringBootTest
class SpringbootTheoryApplicationTests {

    @Autowired
    private ApplicationContext applicationContext; //IOC容器對象

    //獲取bean對象
    @Test
    public void testGetBean(){
        //根據(jù)bean的名稱獲取
        MyController bean1 = (MyController) applicationContext.getBean("myController");
        System.out.println(bean1);

        //根據(jù)bean的類型獲取
        MyController bean2 = applicationContext.getBean(MyController.class);
        System.out.println(bean2);

        //根據(jù)bean的名稱 及 類型獲取
        MyController bean3 = applicationContext.getBean("myController", MyController.class);
        System.out.println(bean3);
    }
}

運(yùn)行結(jié)果:

MyController 構(gòu)造方法執(zhí)行了...
com.wbr.controller.MyController@3835d3fd
com.wbr.controller.MyController@3835d3fd
com.wbr.controller.MyController@3835d3fd

注意事項(xiàng):

  • IOC容器中的bean默認(rèn)使用的作用域:singleton (單例)
  • 默認(rèn)singleton的bean,在容器啟動(dòng)時(shí)被創(chuàng)建,可以使用@Lazy注解來延遲初始化(延遲到第一次使用時(shí))

測試二:

給MyController加上@Scope("prototype")注解:

@Lazy //延遲加載(第一次使用bean對象時(shí),才會(huì)創(chuàng)建bean對象并交給ioc容器管理)
@Scope("prototype")
@RestController
public class MyController {

    @Autowired
    private MyService myService;

    public MyController(){
        System.out.println("MyController 構(gòu)造方法執(zhí)行了...");
    }
}

再次運(yùn)行測試方法得到以下結(jié)果:

MyController 構(gòu)造方法執(zhí)行了...
com.wbr.controller.MyController@73aae7a
MyController 構(gòu)造方法執(zhí)行了...
com.wbr.controller.MyController@3856d0cb
MyController 構(gòu)造方法執(zhí)行了...
com.wbr.controller.MyController@2125535d

注意事項(xiàng):

  • prototype的bean,每一次使用該bean的時(shí)候都會(huì)創(chuàng)建一個(gè)新的實(shí)例
  • 實(shí)際開發(fā)當(dāng)中,絕大部分的Bean是單例的,也就是說絕大部分Bean不需要配置scope屬性

1.3 第三方Bean

情況1:自定義類上加上@Component以及它的這三個(gè)衍生注解@Controller、@Service、@Repository,用來聲明這個(gè)bean對象。

情況2:這個(gè)類它不是我們自己編寫的,而是我們引入的第三方依賴當(dāng)中提供的。

我們可以使用 ObjectMapper 作為第三方依賴。ObjectMapper 是 Jackson 庫中的核心類,用于在 Java 對象和 JSON 之間進(jìn)行轉(zhuǎn)換。

當(dāng)我們需要使用到ObjectMapper對象時(shí),應(yīng)該如何進(jìn)行依賴注入?

由于第三方提供的類是只讀的。無法在第三方類上添加@Component注解或衍生注解。

解決方案1:在啟動(dòng)類上添加用@Bean標(biāo)識的方法

啟動(dòng)類:

@SpringBootApplication
public class SpringbootTheoryApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootTheoryApplication.class, args);
    }

    //聲明第三方bean
    @Bean //將當(dāng)前方法的返回值對象交給IOC容器管理, 成為IOC容器bean
    public ObjectMapper objectMapper(){
        return new ObjectMapper();
    }
}

測試類:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {

    @Autowired
    private ObjectMapper objectMapper;

    // 第三方bean的管理
    @Test
    public void testThirdBean() throws Exception {
        // 將 JSON 字符串轉(zhuǎn)換為 Java 對象
        String json = "{\"name\":\"zhangsan\",\"age\":21}";
        Person person = objectMapper.readValue(json, Person.class);

        System.out.println(person.getName() + " : " + person.getAge());
    }

    // 用于測試的簡單 POJO 類
    static class Person {
        private String name;
        private int age;


        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

運(yùn)行結(jié)果:

zhangsan : 21

注意事項(xiàng):

  • 以上在啟動(dòng)類中聲明第三方Bean的作法,不建議使用(項(xiàng)目中要保證啟動(dòng)類的純粹性)

解決方案2:在配置類中定義@Bean標(biāo)識的方法

  • 如果需要定義第三方Bean時(shí), 通常會(huì)單獨(dú)定義一個(gè)配置類
@Configuration //聲明一個(gè)配置類
public class ObjectMapperConfig {
    
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}

注釋掉SpringBoot啟動(dòng)類中創(chuàng)建第三方bean對象的代碼,重新執(zhí)行測試方法:

zhangsan : 21

在方法上加上一個(gè)@Bean注解,Spring 容器在啟動(dòng)的時(shí)候,它會(huì)自動(dòng)的調(diào)用這個(gè)方法,并將方法的返回值聲明為Spring容器當(dāng)中的Bean對象。

注意事項(xiàng) :

  • 通過@Bean注解的name或value屬性可以聲明bean的名稱,如果不指定,默認(rèn)bean的名稱就是方法名。
  • 如果第三方bean需要依賴其它bean對象,直接在bean定義方法中設(shè)置形參即可,容器會(huì)根據(jù)類型自動(dòng)裝配。

2、SpringBoot原理

SpringBoot框架之所以使用起來更簡單更快捷,是因?yàn)镾pringBoot框架底層提供了兩個(gè)非常重要的功能:一個(gè)是起步依賴,一個(gè)是自動(dòng)配置。

2.1 起步依賴

假如沒有使用SpringBoot,用的是Spring框架進(jìn)行web程序的開發(fā),此時(shí)我們就需要引入web程序開發(fā)所需要的一些依賴。

  • spring-webmvc依賴:這是Spring框架進(jìn)行web程序開發(fā)所需要的依賴
  • servlet-api依賴:Servlet基礎(chǔ)依賴
  • jackson-databind依賴:JSON處理工具包

如果要使用AOP,還需要引入aop依賴、aspect依賴

項(xiàng)目中所引入的這些依賴,還需要保證版本匹配,否則就可能會(huì)出現(xiàn)版本沖突問題。

使用了SpringBoot,就不需要像上面這么繁瑣的引入依賴了。由于Maven的依賴傳遞。我們只需要引入一個(gè)依賴就可以了,那就是web開發(fā)的起步依賴:springboot-starter-web。

在web開發(fā)的起步依賴當(dāng)中,就集成了web開發(fā)中常見的依賴:json、web、webmvc、tomcat等。我們只需要引入這一個(gè)起步依賴,其他的依賴都會(huì)自動(dòng)的通過Maven的依賴傳遞進(jìn)來。

2.2 SpringBoot自動(dòng)裝配

話不多說,上源碼跟蹤圖?。?/strong>

2.3 @Conditional

我們在跟蹤SpringBoot自動(dòng)配置的源碼的時(shí)候,在自動(dòng)配置類聲明bean的時(shí)候,除了在方法上加了一個(gè)@Bean注解以外,還會(huì)經(jīng)常用到一個(gè)注解,就是以Conditional開頭的這一類的注解。

以Conditional開頭的這些注解都是條件裝配的注解。下面我們就來介紹下條件裝配注解。

@Conditional注解:

  • 作用:按照一定的條件進(jìn)行判斷,在滿足給定條件后才會(huì)注冊對應(yīng)的bean對象到Spring的IOC容器中。
  • 位置:方法、類

@Conditional本身是一個(gè)父注解,派生出大量的子注解:

  • @ConditionalOnClass:判斷環(huán)境中有對應(yīng)字節(jié)碼文件,才注冊bean到IOC容器。
  • @ConditionalOnMissingBean:判斷環(huán)境中沒有對應(yīng)的bean(類型或名稱),才注冊bean到IOC容器。
  • @ConditionalOnProperty:判斷配置文件中有對應(yīng)屬性和值,才注冊bean到IOC容器。

下面我們通過代碼來演示下Conditional注解的使用:

  • @ConditionalOnClass注解
@Configuration
public class HeaderConfig {
?
    @Bean
    @ConditionalOnClass(name="io.jsonwebtoken.Jwts")//環(huán)境中存在指定的這個(gè)類,才會(huì)將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
    
}
  • 測試類
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;
?
    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }
}

執(zhí)行testHeaderParser()測試方法:

因?yàn)閕o.jsonwebtoken.Jwts字節(jié)碼文件在啟動(dòng)SpringBoot程序時(shí)已存在,所以創(chuàng)建HeaderParser對象并注冊到IOC容器中。

  • @ConditionalOnMissingBean注解
@Configuration
public class HeaderConfig {
?
    @Bean
    @ConditionalOnMissingBean //不存在該類型的bean,才會(huì)將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
    
}

執(zhí)行testHeaderParser()測試方法:

SpringBoot在調(diào)用@Bean標(biāo)識的headerParser()前,IOC容器中是沒有HeaderParser類型的bean,所以HeaderParser對象正常創(chuàng)建,并注冊到IOC容器中。

再次修改@ConditionalOnMissingBean注解:

@Configuration
public class HeaderConfig {
?
    @Bean
    @ConditionalOnMissingBean(name="deptController2")//不存在指定名稱的bean,才會(huì)將該bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
}

執(zhí)行testHeaderParser()測試方法:

因?yàn)樵赟pringBoot環(huán)境中不存在名字叫deptController2的bean對象,所以創(chuàng)建HeaderParser對象并注冊到IOC容器中。

再次修改@ConditionalOnMissingBean注解:

@Configuration
public class HeaderConfig {
?
    @Bean
    @ConditionalOnMissingBean(HeaderConfig.class)//不存在指定類型的bean,才會(huì)將bean加入IOC容器
    public HeaderParser headerParser(){
        return new HeaderParser();
    }
}
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;
?
    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }
}

執(zhí)行testHeaderParser()測試方法:

因?yàn)镠eaderConfig類中添加@Configuration注解,而@Configuration注解中包含了@Component,所以SpringBoot啟動(dòng)時(shí)會(huì)創(chuàng)建HeaderConfig類對象,并注冊到IOC容器中。

當(dāng)IOC容器中有HeaderConfig類型的bean存在時(shí),不會(huì)把創(chuàng)建HeaderParser對象注冊到IOC容器中。而IOC容器中沒有HeaderParser類型的對象時(shí),通過getBean(HeaderParser.class)方法獲取bean對象時(shí),引發(fā)異常:NoSuchBeanDefinitionException

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決Sentinel鏈路模式規(guī)則無效問題

    解決Sentinel鏈路模式規(guī)則無效問題

    本文介紹了如何在Spring Cloud Alibaba項(xiàng)目中使用Sentinel鏈路流控規(guī)則,并解決規(guī)則不生效的問題,通過關(guān)閉Sentinel過濾器,可以避免重復(fù)統(tǒng)計(jì)請求
    2025-01-01
  • SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的流程步驟

    SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的流程步驟

    優(yōu)雅停機(jī)(Graceful Shutdown) 是指在服務(wù)器需要關(guān)閉或重啟時(shí),能夠先處理完當(dāng)前正在進(jìn)行的請求,然后再停止服務(wù)的操作,本文給大家介紹了SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的流程步驟,需要的朋友可以參考下
    2024-03-03
  • SpringBoot3安全管理操作方法

    SpringBoot3安全管理操作方法

    這篇文章主要介紹了SpringBoot3安全管理,在實(shí)際開發(fā)中,最常用的是登錄驗(yàn)證和權(quán)限體系兩大功能,在登錄時(shí)完成身份的驗(yàn)證,加載相關(guān)信息和角色權(quán)限,在訪問其他系統(tǒng)資源時(shí),進(jìn)行權(quán)限的驗(yàn)證,保護(hù)系統(tǒng)的安全,文中有詳細(xì)的操作步驟,需要的朋友可以參考下
    2023-08-08
  • Java中的Random()函數(shù)及兩種構(gòu)造方法

    Java中的Random()函數(shù)及兩種構(gòu)造方法

    Java中存在著兩種Random函數(shù)分別是java.lang.Math.Random和java.util.Random,文中給大家介紹了random()的兩種構(gòu)造方法,感興趣的朋友跟隨小編一起看看吧
    2018-11-11
  • SpringBoot項(xiàng)目啟動(dòng)后立馬自動(dòng)關(guān)閉的解決方案

    SpringBoot項(xiàng)目啟動(dòng)后立馬自動(dòng)關(guān)閉的解決方案

    這篇文章主要介紹了SpringBoot項(xiàng)目啟動(dòng)后立馬自動(dòng)關(guān)閉的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • java使用FileVisitor遍歷文件和目錄

    java使用FileVisitor遍歷文件和目錄

    這篇文章主要為大家詳細(xì)介紹了java使用FileVisitor遍歷文件和目錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 基于Redis分布式鎖Redisson及SpringBoot集成Redisson

    基于Redis分布式鎖Redisson及SpringBoot集成Redisson

    這篇文章主要介紹了基于Redis分布式鎖Redisson及SpringBoot集成Redisson,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小小伙伴可以參考一下
    2022-09-09
  • SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼

    SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼

    本篇文章主要介紹了SrpingDruid數(shù)據(jù)源加密數(shù)據(jù)庫密碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • springboot-mybatis/JPA流式查詢的多種實(shí)現(xiàn)方式

    springboot-mybatis/JPA流式查詢的多種實(shí)現(xiàn)方式

    這篇文章主要介紹了springboot-mybatis/JPA流式查詢,本文給大家分享三種方式,每種方式結(jié)合示例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • java動(dòng)態(tài)代理(jdk與cglib)詳細(xì)解析

    java動(dòng)態(tài)代理(jdk與cglib)詳細(xì)解析

    靜態(tài)代理:由程序員創(chuàng)建或特定工具自動(dòng)生成源代碼,再對其編譯。在程序運(yùn)行前,代理類的.class文件就已經(jīng)存在了
    2013-09-09

最新評論