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

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

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

1、Bean管理

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

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

1.1 獲取Bean

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

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

@Autowired
private ApplicationContext applicationContext; //IOC容器對(duì)象

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

介紹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容器對(duì)象

    //獲取bean對(duì)象
    @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é)果都是一樣的,說(shuō)明IOC容器當(dāng)中的bean對(duì)象只有一個(gè)。

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

1.2 Bean的作用域

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

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

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

作用域說(shuō)明
singleton容器內(nèi)同名稱的bean只有一個(gè)實(shí)例(單例)(默認(rèn))
prototype每次使用該bean時(shí)會(huì)創(chuàng)建新的實(shí)例(非單例)
request每個(gè)請(qǐng)求范圍內(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注解來(lái)進(jìn)行配置作用域

測(cè)試一:

Controller類

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

    @Autowired
    private MyService myService;

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

測(cè)試類

@SpringBootTest
class SpringbootTheoryApplicationTests {

    @Autowired
    private ApplicationContext applicationContext; //IOC容器對(duì)象

    //獲取bean對(duì)象
    @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注解來(lái)延遲初始化(延遲到第一次使用時(shí))

測(cè)試二:

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

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

    @Autowired
    private MyService myService;

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

再次運(yùn)行測(cè)試方法得到以下結(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í)際開(kāi)發(fā)當(dāng)中,絕大部分的Bean是單例的,也就是說(shuō)絕大部分Bean不需要配置scope屬性

1.3 第三方Bean

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

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

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

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

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

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

啟動(dòng)類:

@SpringBootApplication
public class SpringbootTheoryApplication {

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

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

測(cè)試類:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {

    @Autowired
    private ObjectMapper objectMapper;

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

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

    // 用于測(cè)試的簡(jiǎn)單 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)識(shí)的方法

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

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

zhangsan : 21

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

注意事項(xiàng) :

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

2、SpringBoot原理

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

2.1 起步依賴

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

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

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

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

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

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

2.2 SpringBoot自動(dòng)裝配

話不多說(shuō),上源碼跟蹤圖??!

2.3 @Conditional

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

以Conditional開(kāi)頭的這些注解都是條件裝配的注解。下面我們就來(lái)介紹下條件裝配注解。

@Conditional注解:

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

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

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

下面我們通過(guò)代碼來(lái)演示下Conditional注解的使用:

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

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

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

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

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

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

再次修改@ConditionalOnMissingBean注解:

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

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

因?yàn)樵赟pringBoot環(huán)境中不存在名字叫deptController2的bean對(duì)象,所以創(chuàng)建HeaderParser對(duì)象并注冊(cè)到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()測(cè)試方法:

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

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

總結(jié)

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

相關(guān)文章

  • java中找不到符號(hào)的解決方案

    java中找不到符號(hào)的解決方案

    這篇文章主要介紹了java中找不到符號(hào)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Java并發(fā)編程之Fork/Join框架詳解

    Java并發(fā)編程之Fork/Join框架詳解

    這篇文章主要介紹了Java并發(fā)編程之Fork/Join框架詳解,Fork/Join框架是Java7提供的一個(gè)用于并行執(zhí)行任務(wù)的框架,是一個(gè)把大任務(wù)分割成若干個(gè)小任務(wù),最終匯總每個(gè)小任務(wù)結(jié)果后得到大任務(wù)結(jié)果的框架,需要的朋友可以參考下
    2023-12-12
  • SpringMVC實(shí)現(xiàn)自定義類型轉(zhuǎn)換器

    SpringMVC實(shí)現(xiàn)自定義類型轉(zhuǎn)換器

    本篇文章主要介紹了SpringMVC實(shí)現(xiàn)自定義類型轉(zhuǎn)換器 ,詳細(xì)的介紹了自定義類型轉(zhuǎn)換器的用法和好處,有興趣的可以了解一下。
    2017-04-04
  • 使用Cloud Toolkit在IDEA中極速創(chuàng)建dubbo工程

    使用Cloud Toolkit在IDEA中極速創(chuàng)建dubbo工程

    這篇文章主要介紹了使用Cloud Toolkit在IDEA中極速創(chuàng)建dubbo工程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • ResultSet如何動(dòng)態(tài)獲取列名和值

    ResultSet如何動(dòng)態(tài)獲取列名和值

    這篇文章主要介紹了ResultSet如何動(dòng)態(tài)獲取列名和值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • SpringBoot中實(shí)現(xiàn)定時(shí)任務(wù)的幾種方式

    SpringBoot中實(shí)現(xiàn)定時(shí)任務(wù)的幾種方式

    定時(shí)任務(wù)在我們項(xiàng)目開(kāi)發(fā)中也是很重要的,對(duì)于某些場(chǎng)景必須要用定時(shí)任務(wù)?,如定時(shí)發(fā)送郵件啊,定時(shí)統(tǒng)計(jì)數(shù)據(jù)等,這篇文章主要講講項(xiàng)目中實(shí)現(xiàn)定時(shí)任務(wù)的幾種方式,需要的朋友可以參考下
    2023-05-05
  • Java Stream 流實(shí)現(xiàn)合并操作示例

    Java Stream 流實(shí)現(xiàn)合并操作示例

    這篇文章主要介紹了Java Stream 流實(shí)現(xiàn)合并操作,結(jié)合實(shí)例形式詳細(xì)分析了Java Stream 流實(shí)現(xiàn)合并操作原理與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • Java21虛擬線程實(shí)踐

    Java21虛擬線程實(shí)踐

    java21正式版發(fā)布了,為我們帶來(lái)了很多新的特性,其中我最感興趣的就是虛擬線程,本文主要介紹了Java21虛擬線程實(shí)踐,感興趣的可以;了解一下
    2023-10-10
  • Jersey Restful接口如何獲取參數(shù)的問(wèn)題

    Jersey Restful接口如何獲取參數(shù)的問(wèn)題

    這篇文章主要介紹了Jersey Restful接口如何獲取參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java代碼審計(jì)的一些基礎(chǔ)知識(shí)你知道嗎

    Java代碼審計(jì)的一些基礎(chǔ)知識(shí)你知道嗎

    這篇文章主要介紹了基于Java的代碼審計(jì)功能的基礎(chǔ)知識(shí),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-09-09

最新評(píng)論

望城县| 开化县| 巴林右旗| 札达县| 阳高县| 肇州县| 无锡市| 沂南县| 三原县| 紫金县| 鄂托克前旗| 子长县| 崇州市| 兴山县| 将乐县| 开化县| 延庆县| 望都县| 黑水县| 湖口县| 论坛| 东兰县| 湄潭县| 新野县| 台前县| 邵武市| 平利县| 全南县| 岚皋县| 宜丰县| 宜君县| 三门县| 广元市| 容城县| 石城县| 太白县| 芜湖县| 天峨县| 南木林县| 平和县| 娄底市|