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

Spring?Boot?底層原理基礎深度解析

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

1. 底層注解@Configuration

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

項目基本結構:

 兩個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 應用
 */
//@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) 注解。 該注解告訴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 時,這種依賴關系成立
        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 應用
 */
//@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));
    }
}

運行結果:

可以看出,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 時,這種依賴關系成立
        dragonUser.setPet(pet01());
        return dragonUser;
    }
    @Bean("tomcatPet")
    public Pet pet01(){
        return new Pet("dragonPet");
}

運行結果:

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

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

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

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

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

2. 底層注解@Import

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

接下來,實踐一下:

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

主類加入如下測試:

 運行結果:

 結果說明:

“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 操作與設置筆記

http://www.dbjr.com.cn/article/208232.htm

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

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

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

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

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

相關文章

  • 深入探究Java線程與進程有哪些區(qū)別

    深入探究Java線程與進程有哪些區(qū)別

    這篇文章主要介紹了Java并發(fā)編程之線程創(chuàng)建,進程是代碼在數(shù)據(jù)集合上的一次運行活動,是系統(tǒng)進行資源分配和調(diào)度的基本單位,線程則是一個實體,一個進程中至少有一個線程,下文更多相關內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • SpringBoot多數(shù)據(jù)源配置詳細教程(JdbcTemplate、mybatis)

    SpringBoot多數(shù)據(jù)源配置詳細教程(JdbcTemplate、mybatis)

    這篇文章主要介紹了SpringBoot多數(shù)據(jù)源配置詳細教程(JdbcTemplate、mybatis),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • 解決IDEA?2022?Translation?翻譯文檔失敗:?未知錯誤的問題

    解決IDEA?2022?Translation?翻譯文檔失敗:?未知錯誤的問題

    這篇文章主要介紹了IDEA?2022?Translation?翻譯文檔失敗:?未知錯誤,本文較詳細的給大家介紹了IDEA?2022?Translation未知錯誤翻譯文檔失敗的解決方法,需要的朋友可以參考下
    2022-04-04
  • MyBatis中#{}占位符與${}拼接符的用法說明

    MyBatis中#{}占位符與${}拼接符的用法說明

    這篇文章主要介紹了MyBatis中#{}占位符與${}拼接符的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java SpringMVC數(shù)據(jù)響應超詳細講解

    Java SpringMVC數(shù)據(jù)響應超詳細講解

    Spring?MVC?是?Spring?提供的一個基于?MVC?設計模式的輕量級?Web?開發(fā)框架,本質(zhì)上相當于?Servlet,Spring?MVC?角色劃分清晰,分工明細,本章來講解SpringMVC數(shù)據(jù)響應
    2022-04-04
  • 基于java實現(xiàn)人機猜拳游戲

    基于java實現(xiàn)人機猜拳游戲

    這篇文章主要為大家詳細介紹了基于java實現(xiàn)人機猜拳游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Spring Boot 2和Redis例子實現(xiàn)過程解析

    Spring Boot 2和Redis例子實現(xiàn)過程解析

    這篇文章主要介紹了Spring Boot2發(fā)布與調(diào)用REST服務過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • Java實現(xiàn)通訊錄管理系統(tǒng)項目

    Java實現(xiàn)通訊錄管理系統(tǒng)項目

    這篇文章主要為大家詳細介紹了Java實現(xiàn)通訊錄管理系統(tǒng)項目,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java實現(xiàn)簡單的掃雷小程序

    Java實現(xiàn)簡單的掃雷小程序

    這篇文章主要為大家詳細介紹了Java實現(xiàn)簡單的掃雷小程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • java反射機制的一些學習心得小結

    java反射機制的一些學習心得小結

    這篇文章主要給大家介紹了關于java反射機制的一些學習心得,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02

最新評論