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

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

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

1. 底層注解@Configuration

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

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

 兩個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標注在方法上給容器注冊組件,默認也是單實例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full(proxyBeanMethods = true): 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
 *      Lite(proxyBeanMethods = false): 在容器中不會保留代理對象,外部多次調(diào)用這些組件時,每次調(diào)用都會產(chǎn)生一個新的對象
 *      用于解決組件依賴場景
 */
@Configuration(proxyBeanMethods = true)  //告訴SpringBoot 這是一個配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實例
    public User user01(){
        return new User("dragon",18);
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

主類MainApplication.java 中測試調(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;
/**
 * 主程序類
 * 這個注解相當于告訴Spring Boot: 這是一個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)代理對象調(diào)用方法, Spring Boot 總會檢查這個組件是否在容器中有,如果有則不會新建,保持組件單實例。
        User user01 = myConfig.user01();
        User user02 = myConfig.user01();
        System.out.println(user01 == user02);
    }
}

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

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

1. 該注解的配置類里面使用@Bean標注在方法上給容器注冊組件,默認也是單實例的。

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

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

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

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

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

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

實踐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對象對用pet對象,同時使用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標注在方法上給容器注冊組件,默認也是單實例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full模式(proxyBeanMethods = true): 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
 *      Lite模式(proxyBeanMethods = false): 在容器中不會保留代理對象,外部多次調(diào)用這些組件時,每次調(diào)用都會產(chǎn)生一個新的對象
 *      用于解決組件依賴場景
 */
@Configuration(proxyBeanMethods = true)  //告訴SpringBoot 這是一個配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實例
    public User user01(){
        User dragonUser = new User("dragon",18);
        // User 組件依賴了Pet 組件,當proxyBeanMethods 為 true 時,這種依賴關(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;
/**
 * 主程序類
 * 這個注解相當于告訴Spring Boot: 這是一個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)代理對象調(diào)用方法, Spring Boot 總會檢查這個組件是否在容器中有,如果有則不會新建,保持組件單實例。
        User user01 = myConfig.user01();
        User user02 = myConfig.user01();
        System.out.println(user01 == user02);
        //測試 @Configuration(proxyBeanMethods = true/false)
        User user011 = run.getBean("user01", User.class);
        Pet tomcatPet = run.getBean("tomcatPet", Pet.class);
        System.out.println("用戶的寵物:" + (user011.getPet() == tomcatPet));
    }
}

運行結(jié)果:

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

接下來,改用Lite模式(proxyBeanMethods = false):即基于上面實例,將配置類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標注在方法上給容器注冊組件,默認也是單實例的
 * 2. 配置類本身也是組件
 * 3. proxyBeanMethods: 代理Bean 方法:
 *      Full模式(proxyBeanMethods = true): 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
 *      Lite模式(proxyBeanMethods = false): 在容器中不會保留代理對象,外部多次調(diào)用這些組件時,每次調(diào)用都會產(chǎn)生一個新的對象
 *      用于解決組件依賴場景
 */
@Configuration(proxyBeanMethods = false)  //告訴SpringBoot 這是一個配置類 == 以前的配置文件
public class MyConfig {
    /**
     * 外部無論對配置類中的這個組件注冊方法調(diào)用多少次,獲取的都是之前注冊容器中的單實例對象
     * @return
     */
    @Bean   //給容器中添加組件,以方法名作為主鍵id,返回類型就是組件類型,返回值就是組件在容器中的實例
    public User user01(){
        User dragonUser = new User("dragon",18);
        // User 組件依賴了Pet 組件,當proxyBeanMethods 為 true 時,這種依賴關(guān)系成立
        dragonUser.setPet(pet01());
        return dragonUser;
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

運行結(jié)果:

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

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

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

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

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

2. 底層注解@Import

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

接下來,實踐一下:

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

主類加入如下測試:

 運行結(jié)果:

 結(jié)果說明:

“com.menergy.boot.bean.User” 是通過@Import 導入的組件。(默認的組件名稱是全類名

“user01” 是之前用@Bean 方法添加進去的

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

3. 底層注解@Conditional

@Conditional 是條件裝配:當滿足@Conditional指定的條件時, 才向容器中注入組件。

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

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

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

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

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

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

接下來,以@ConditionalOnBean 為例,進行實踐:

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

相關(guān)文章

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

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

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

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

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

    java反射簡單實例

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

    Java中ShardingSphere分庫分表實戰(zhàn)

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

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

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

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

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

    Java?SpringBoot核心源碼詳解

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

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

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

    詳解spring boot rest例子

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

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

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

最新評論

和顺县| 客服| 同江市| 台东市| 黄陵县| 甘南县| 洛隆县| 商南县| 上栗县| 商都县| 德化县| 罗源县| 奉化市| 茌平县| 洪江市| 沐川县| 定西市| 吴旗县| 台山市| 南川市| 岳阳市| 定日县| 久治县| 望谟县| 武威市| 双柏县| 红安县| 星子县| 武山县| 忻州市| 呼和浩特市| 西丰县| 金秀| 莒南县| 德惠市| 汽车| 太白县| 钦州市| 启东市| 边坝县| 太白县|