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

Spring?Boot?底層原理基礎(chǔ)深度解析

 更新時(shí)間:2022年04月03日 10:24:26   作者:龍泉太阿  
這篇文章主要介紹了Spring?Boot?底層原理基礎(chǔ),包括底層注解@Configuration,底層注解@Import及底層注解@Conditional的相關(guān)知識(shí),本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

1. 底層注解@Configuration

@Configuration 注解主要用于給容器添加組件(Bean),下面實(shí)踐其用法:

項(xiàng)目基本結(jié)構(gòu):

 兩個(gè)Bean組件:

User.java

package com.menergy.boot.bean;
 
/**
 * 用戶
 */
public class User {
    private String name;
    private Integer age;
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    public String getName() {
        return name;
    public void setName(String name) {
    public Integer getAge() {
        return age;
    public void setAge(Integer age) {
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
}

Pet.java

package com.menergy.boot.bean;
 
/**
 * 寵物
 */
public class Pet {
    private String name;
    public Pet() {
    }
    public Pet(String name) {
        this.name = name;
    public String getName() {
        return name;
    public void setName(String name) {
    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                '}';
}

以前Spring 配置文件方式是這樣給容器添加組件的:

<beans>
 
    <bean id="user01" class="com.menergy.boot.bean.User">
        <property name="name" value="dragon"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="pet01" class="com.menergy.boot.bean.Pet">
        <property name="name" value="dragonPet"></property>
</beans>

現(xiàn)在Spring Boot 已經(jīng)不寫上面的xml配置了,在Spring Boot 底層可以用@Configuration 注解給容器中添加組件。如下:

注解類MyConfig.java

package com.menergy.boot.config;
 
import com.menergy.boot.bean.Pet;
import com.menergy.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 1. 配置類里面使用@Bean標(biāo)注在方法上給容器注冊(cè)組件,默認(rèn)也是單實(shí)例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full(proxyBeanMethods = true): 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
 *      Lite(proxyBeanMethods = false): 在容器中不會(huì)保留代理對(duì)象,外部多次調(diào)用這些組件時(shí),每次調(diào)用都會(huì)產(chǎn)生一個(gè)新的對(duì)象
 *      用于解決組件依賴場(chǎng)景
 */
@Configuration(proxyBeanMethods = true)  //告訴SpringBoot 這是一個(gè)配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實(shí)例
    public User user01(){
        return new User("dragon",18);
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

主類MainApplication.java 中測(cè)試調(diào)用:

package com.menergy.boot;
 
import com.menergy.boot.bean.Pet;
import com.menergy.boot.bean.User;
import com.menergy.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import sun.awt.geom.AreaOp;
/**
 * 主程序類
 * 這個(gè)注解相當(dāng)于告訴Spring Boot: 這是一個(gè)Spring boot 應(yīng)用
 */
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.menergy.boot")
public class MainApplication {
    public static void main(String[] args) {
//        SpringApplication.run(MainApplication.class, args);
        // 1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2.查看容器里面的容器
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        // 3. 從容器中獲取組件
        Pet pet1 = run.getBean("tomcatPet", Pet.class);
        Pet pet2 = run.getBean("tomcatPet", Pet.class);
        System.out.println("組件: " + (pet1 == pet2));
        // 4. com.menergy.boot.config.MyConfig$$EnhancerBySpringCGLIB$$3779496a@67a056f1
        MyConfig myConfig = run.getBean(MyConfig.class);
        System.out.println(myConfig);
        //如果@Configuration(proxyBeanMethods = true)代理對(duì)象調(diào)用方法, Spring Boot 總會(huì)檢查這個(gè)組件是否在容器中有,如果有則不會(huì)新建,保持組件單實(shí)例。
        User user01 = myConfig.user01();
        User user02 = myConfig.user01();
        System.out.println(user01 == user02);
    }
}

輸出的部分結(jié)果:

上面的例子,重點(diǎn)落在@Configuration(proxyBeanMethods = true) 注解。 該注解告訴SpringBoot ,被注解的類是一個(gè)配置類, 相當(dāng)于以前的配置文件xml中的“bean配置”。該注解有如下特性:

1. 該注解的配置類里面使用@Bean標(biāo)注在方法上給容器注冊(cè)組件,默認(rèn)也是單實(shí)例的。

2. 被這個(gè)注解的配置類本身也是組件。

3. 該注解的屬性proxyBeanMethods 可以通過“true” 和 “false” 配置值,來(lái)控制使用的模式:

        (1)Full模式(proxyBeanMethods = true): 為true時(shí),外部無(wú)論對(duì)配置類中的組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象。

        (2)Lite模式(proxyBeanMethods = false): 為false時(shí),在容器中不會(huì)保留代理對(duì)象,外部多次調(diào)用這些組件時(shí),每次調(diào)用都會(huì)產(chǎn)生一個(gè)新的對(duì)象。

        這兩種模式的存在主要用于解決組件依賴場(chǎng)景。

1和2 兩點(diǎn)特性上面的例子中都有體現(xiàn), 接下來(lái)重點(diǎn)實(shí)踐第三點(diǎn)特性:

實(shí)踐proxyBeanMethods:

基于上面的例子,首先修改User.java類,加上寵物Pet的依賴:

package com.menergy.boot.bean;
 
/**
 * 用戶
 */
public class User {
    private String name;
    private Integer age;
    private Pet pet;
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    public User(String name, Integer age, Pet pet) {
        this.pet = pet;
    public String getName() {
        return name;
    public void setName(String name) {
    public Integer getAge() {
        return age;
    public void setAge(Integer age) {
    public Pet getPet() {
        return pet;
    public void setPet(Pet pet) {
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", pet=" + pet +
                '}';
}

 在配置類MyConfig.java 中加入user01對(duì)象對(duì)用pet對(duì)象,同時(shí)使用Full模式(proxyBeanMethods = true):

package com.menergy.boot.config;
 
import com.menergy.boot.bean.Pet;
import com.menergy.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 1. 配置類里面使用@Bean標(biāo)注在方法上給容器注冊(cè)組件,默認(rèn)也是單實(shí)例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full模式(proxyBeanMethods = true): 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
 *      Lite模式(proxyBeanMethods = false): 在容器中不會(huì)保留代理對(duì)象,外部多次調(diào)用這些組件時(shí),每次調(diào)用都會(huì)產(chǎn)生一個(gè)新的對(duì)象
 *      用于解決組件依賴場(chǎng)景
 */
@Configuration(proxyBeanMethods = true)  //告訴SpringBoot 這是一個(gè)配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實(shí)例
    public User user01(){
        User dragonUser = new User("dragon",18);
        // User 組件依賴了Pet 組件,當(dāng)proxyBeanMethods 為 true 時(shí),這種依賴關(guān)系成立
        dragonUser.setPet(pet01());
        return dragonUser;
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

主類MainApplication.java:

package com.menergy.boot;
 
import com.menergy.boot.bean.Pet;
import com.menergy.boot.bean.User;
import com.menergy.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import sun.awt.geom.AreaOp;
/**
 * 主程序類
 * 這個(gè)注解相當(dāng)于告訴Spring Boot: 這是一個(gè)Spring boot 應(yīng)用
 */
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.menergy.boot")
public class MainApplication {
    public static void main(String[] args) {
//        SpringApplication.run(MainApplication.class, args);
        // 1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        // 2.查看容器里面的容器
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        // 3. 從容器中獲取組件
        Pet pet1 = run.getBean("tomcatPet", Pet.class);
        Pet pet2 = run.getBean("tomcatPet", Pet.class);
        System.out.println("組件: " + (pet1 == pet2));
        // 4. com.menergy.boot.config.MyConfig$$EnhancerBySpringCGLIB$$3779496a@67a056f1
        MyConfig myConfig = run.getBean(MyConfig.class);
        System.out.println(myConfig);
        //如果@Configuration(proxyBeanMethods = true)代理對(duì)象調(diào)用方法, Spring Boot 總會(huì)檢查這個(gè)組件是否在容器中有,如果有則不會(huì)新建,保持組件單實(shí)例。
        User user01 = myConfig.user01();
        User user02 = myConfig.user01();
        System.out.println(user01 == user02);
        //測(cè)試 @Configuration(proxyBeanMethods = true/false)
        User user011 = run.getBean("user01", User.class);
        Pet tomcatPet = run.getBean("tomcatPet", Pet.class);
        System.out.println("用戶的寵物:" + (user011.getPet() == tomcatPet));
    }
}

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

可以看出,F(xiàn)ull模式(proxyBeanMethods = true)時(shí),輸出true,說明是從容器中獲取的同一個(gè)組件(用戶的寵物就是容器中的寵物)。

接下來(lái),改用Lite模式(proxyBeanMethods = false):即基于上面實(shí)例,將配置類MyConfig.java 中的注解的屬性proxyBeanMethods 改成false值,如下:

MyConfig.java:

package com.menergy.boot.config;
 
import com.menergy.boot.bean.Pet;
import com.menergy.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 1. 配置類里面使用@Bean標(biāo)注在方法上給容器注冊(cè)組件,默認(rèn)也是單實(shí)例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full模式(proxyBeanMethods = true): 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
 *      Lite模式(proxyBeanMethods = false): 在容器中不會(huì)保留代理對(duì)象,外部多次調(diào)用這些組件時(shí),每次調(diào)用都會(huì)產(chǎn)生一個(gè)新的對(duì)象
 *      用于解決組件依賴場(chǎng)景
 */
@Configuration(proxyBeanMethods = false)  //告訴SpringBoot 這是一個(gè)配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無(wú)論對(duì)配置類中的這個(gè)組件注冊(cè)方法調(diào)用多少次,獲取的都是之前注冊(cè)容器中的單實(shí)例對(duì)象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實(shí)例
    public User user01(){
        User dragonUser = new User("dragon",18);
        // User 組件依賴了Pet 組件,當(dāng)proxyBeanMethods 為 true 時(shí),這種依賴關(guān)系成立
        dragonUser.setPet(pet01());
        return dragonUser;
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

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

 可以看出,Lite模式(proxyBeanMethods = false)時(shí),輸出false,說明是從容器中獲取的不是同一個(gè)組件(用戶的寵物不是容器中的寵物, 相當(dāng)于new 了另一個(gè)對(duì)象)。

總結(jié):配置類包括了全模式(Full)和輕量級(jí)模式(Lite)兩種。當(dāng)proxyBeanMethods 是true時(shí),Spring Boot 每次都會(huì)檢查容器中是否有相應(yīng)的組件,如果proxyBeanMethods 是false, 則不檢查容器中是否有沒有相應(yīng)的組件,而是直接new一個(gè)。這也是Spring Boot 新增的一個(gè)很重要的特性。

最佳實(shí)戰(zhàn):如果只是向容器中增加組件,別的地方也不會(huì)調(diào)用這個(gè)組件,我們可以將其調(diào)為false 模式,這樣Spring Boot 啟動(dòng)起來(lái)非???,加載起來(lái)也非???。 如果別的地方明顯要用,要依賴,我們就把其調(diào)成true,保證依賴的組件就是容器中的組件。

注: 前面的例子中,在配置類中用到@Been 注解來(lái)指定組件, 其實(shí)Spring Boot 底層還用到了其他一些以前常用的注解來(lái)指定組件,包括@Component、@Controller、@Service、@Repository。這些類似于@Been 原理,也是用于向容器中注冊(cè)組件。

除此之外,底層還用到@ComponentScan 注解來(lái)說明容器的包掃描,還有@Import 和@Conditional 來(lái)向容器添加組件。很多注解是以前常用的,接下來(lái)主要說明@Import 和@Conditional 注解。

2. 底層注解@Import

首先,從@Import 注解類中可以看到該注解的定義,以及知道其屬性是一個(gè)Class類型的數(shù)組,說明這個(gè)注解的作用是向容器中導(dǎo)入一批組件

接下來(lái),實(shí)踐一下:

 首先在配置類上加入@Import 注解,并向容器中導(dǎo)入兩個(gè)組件,一個(gè)是自己定義的類,一個(gè)是從第三方Jar 包中任意的一個(gè)類:

主類加入如下測(cè)試:

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

 結(jié)果說明:

“com.menergy.boot.bean.User” 是通過@Import 導(dǎo)入的組件。(默認(rèn)的組件名稱是全類名

“user01” 是之前用@Bean 方法添加進(jìn)去的

“org.apache.logging.log4j.util.StringBuilders@4482469c” 也是通過@Import 導(dǎo)入的組件。

3. 底層注解@Conditional

@Conditional 是條件裝配:當(dāng)滿足@Conditional指定的條件時(shí), 才向容器中注入組件。

在全局Jar包中搜索@Conditional 類:雙擊Shift鍵,選擇Classes,輸入@Conditional搜索。

注:如果調(diào)不出這個(gè)窗口,請(qǐng)參考:IDEA 操作與設(shè)置筆記

http://m.fzitv.net/article/208232.htm

打開Conditional 類后,“Ctrl + H” 鍵調(diào)出這個(gè)類的繼承樹:

 注:如果快捷鍵失效,請(qǐng)確定如下快捷鍵設(shè)置:

從前面的@Conditional 的繼承樹可以看出,@Conditional 有非常多的派生注解,每個(gè)注解都代表不同的功能,從派生注解的注解名稱可以大概知道其功能用意,例如@ConditionalOnBean 注解代表當(dāng)容器中存在某個(gè)Bean時(shí)才干某些事情, @ConditionalOnMissingBean 注解代表當(dāng)容器中不存在某個(gè)Bean時(shí)才干某些事情。

接下來(lái),以@ConditionalOnBean 為例,進(jìn)行實(shí)踐:

到此這篇關(guān)于Spring Boot 底層原理基礎(chǔ)的文章就介紹到這了,更多相關(guān)Spring Boot 底層原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • gradle中的增量構(gòu)建淺析

    gradle中的增量構(gòu)建淺析

    這篇文章主要介紹了gradle中的增量構(gòu)建,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Retrofit+Rxjava下載文件進(jìn)度的實(shí)現(xiàn)

    Retrofit+Rxjava下載文件進(jìn)度的實(shí)現(xiàn)

    這篇文章主要介紹了Retrofit+Rxjava下載文件進(jìn)度的實(shí)現(xiàn),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-11-11
  • java反射簡(jiǎn)單實(shí)例

    java反射簡(jiǎn)單實(shí)例

    這篇文章主要介紹了java反射機(jī)制,以一個(gè)簡(jiǎn)單實(shí)例形式分析了Java反射的原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-02-02
  • Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn)

    Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn)

    我們做項(xiàng)目的時(shí)候,數(shù)據(jù)量比較大,單表千萬(wàn)級(jí)別的,需要分庫(kù)分表,本文主要介紹了Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn),感興趣的可以了解一下
    2021-09-09
  • JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案

    JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案

    本文主要介紹了JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • Scala常用List列表操作方法示例

    Scala常用List列表操作方法示例

    這篇文章主要介紹了Scala常用List列表操作方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Java?SpringBoot核心源碼詳解

    Java?SpringBoot核心源碼詳解

    這篇文章主要為大家介紹了Java?SpringBoot核心源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-12-12
  • javaweb圖書商城設(shè)計(jì)之圖書模塊(4)

    javaweb圖書商城設(shè)計(jì)之圖書模塊(4)

    這篇文章主要介紹了javaweb圖書商城設(shè)計(jì)之圖書模塊的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • 詳解spring boot rest例子

    詳解spring boot rest例子

    這篇文章主要介紹了詳解spring boot rest例子,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-03-03
  • 如何用Eureka + Feign搭建分布式微服務(wù)

    如何用Eureka + Feign搭建分布式微服務(wù)

    Eureka是Spring Cloud Netflix的一部分,是一個(gè)服務(wù)注冊(cè)中心。其服務(wù)生態(tài)中主要有三個(gè)角色:Eureka注冊(cè)中心、服務(wù)提供者、服務(wù)消費(fèi)者。服務(wù)提供者注冊(cè)到Eureka后,服務(wù)消費(fèi)者就能夠直接向Eureka查詢當(dāng)前有哪些服務(wù)可用,再?gòu)闹羞x取一個(gè)消費(fèi).本文講解如何搭建分布式微服務(wù)
    2021-06-06

最新評(píng)論

开原市| 勃利县| 佛冈县| 福鼎市| 肥乡县| 桦甸市| 福清市| 商城县| 高州市| 辉县市| 渑池县| 徐水县| 出国| 陕西省| 屯昌县| 六安市| 松潘县| 休宁县| 红桥区| 理塘县| 耒阳市| 安义县| 三都| 突泉县| 雷州市| 泽州县| 桓台县| 眉山市| 山西省| 徐汇区| 米脂县| 南汇区| 蒙阴县| 台江县| 山阳县| 方山县| 临朐县| 乳山市| 平乐县| 沙坪坝区| 安陆市|