<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Boot 2從入門到入墳 | 底層注解篇:@Configuration詳解

          共 28312字,需瀏覽 57分鐘

           ·

          2021-05-11 17:59

          點擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時間送達(dá)

          76套java從入門到精通實戰(zhàn)課程分享

          為了后面能深入的掌握Spring Boot的自動配置原理,我們得先來看一下Spring Boot的一些底層注解,要知道它們是如何完成相關(guān)功能的。首先,我們來看一下怎么給容器里面添加組件。

          我在這兒準(zhǔn)備了兩個組件,它們分別是:

          • 用戶,即User類

          package com.meimeixia.boot.bean;

          /**
          * @author liayun
          * @create 2021-04-23 19:14
          *
          * 用戶
          */
          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) {
                  this.name = name;
              }

              public Integer getAge() {
                  return age;
              }

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

              @Override
              public String toString() {
                  return "User{" +
                          "name='" + name + '\'' +
                          ", age=" + age +
                          '
          }';
              }

          }

          • 寵物,即Pet類

          package com.meimeixia.boot.bean;

          /**
          * @author liayun
          * @create 2021-04-23 19:16
          *
          * 寵物
          */
          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) {
                  this.name = name;
              }

              @Override
              public String toString() {
                  return "Pet{" +
                          "name='" + name + '\'' +
                          '
          }';
              }

          }

          如果我們是用以前原生的Spring來把以上這兩個組件添加到容器中,那么我們應(yīng)該是要這么來做的,即首先來創(chuàng)建一個Spring的配置文件,例如beans.xml,記住該文件得在src > main > resources目錄下喲,然后使用<bean>標(biāo)簽來向容器中添加組件,如下所示。

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

              <bean id="user01" class="com.meimeixia.boot.bean.User">
                  <property name="name" value="zhangsan"></property>
                  <property name="age" value="18"></property>
              </bean>

              <bean id="cat" class="com.meimeixia.boot.bean.Pet">
                  <property name="name" value="tomcat"></property>
              </bean>

          </beans>

          現(xiàn)在,容器中就會有兩個組件了,一個是User組件,一個是Pet組件。當(dāng)然了,這是我們使用以前Spring XML配置文件的方式來向容器中注冊組件的。

          但是,我們現(xiàn)在使用的是Spring Boot,它已經(jīng)不推薦我們使用Spring XML配置文件的這種方式了,既然不用Spring XML配置文件,那么它是怎么給容器中添加組件的呢?笨蛋,當(dāng)然是使用注解唄??,而且Spring Boot還有好幾種辦法向容器中注冊組件呢!這里,我們先來看第一種辦法吧!

          由于我們使用了Spring Boot之后,已經(jīng)不再寫配置文件了,所以要向容器中注冊組件,我們得使用Spring Boot底層一個叫@Configuration的注解了,該注解翻譯過來就是配置的意思。不妨我們就新建一個類,例如MyConfig,然后我們給該類上標(biāo)注上@Configuration這么一個注解,如下所示。

          package com.meimeixia.boot.config;

          import org.springframework.context.annotation.Configuration;

          /**
           * @author liayun
           * @create 2021-04-23 19:42
           *
           */
          @Configuration // 告訴Spring Boot這是一個配置類 == 配置文件
          public class MyConfig {


          }

          其實,我們這樣的做法(即創(chuàng)建一個類,然后在類上標(biāo)注@Configuration注解)就是類似于創(chuàng)建了一個配置文件,在類上標(biāo)注@Configuration注解,就相當(dāng)于告訴Spring Boot這個文件是一個Spring XML配置文件。你現(xiàn)在明白了吧!@Configuration注解就是來告訴Spring Boot它標(biāo)注的類是一個配置類的。

          以前,我們能在Spring XML配置文件里面能做什么,我們現(xiàn)在也能做什么。以前我們是在配置文件里面使用<bean>標(biāo)簽向容器中添加組件的,現(xiàn)在,在配置類里面我們就不能寫標(biāo)簽了,而是要寫一個方法,比如現(xiàn)在想要向容器中添加一個User組件,我們就得在MyConfig配置類里面編寫如下這樣一個方法。

          package com.meimeixia.boot.config;

          import com.meimeixia.boot.bean.User;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;

          /**
           * @author liayun
           * @create 2021-04-23 19:42
           *
           */
          @Configuration // 告訴Spring Boot這是一個配置類 == 配置文件
          public class MyConfig {

              @Bean // @Bean注解是給容器中添加組件的。添加什么組件呢?以方法名作為組件的id,返回類型就是組件類型,返回的值就是組件在容器中的實例
              public User user01() {
                  User zhangsan = new User("zhangsan", 18);
                  return zhangsan;
              }

          }

          可以看到,我們在以上user01方法上標(biāo)注了一個@Bean注解,該注解是用于給容器中注冊組件的。那注冊什么組件呢?就拿以上user01方法來說,注冊的組件是這樣子的:

          • 方法名(即user01)作為組件的id

          • 方法的返回類型(即com.meimeixia.boot.bean.User)作為組件的類型

          • 方法返回的值(即User對象)作為組件在容器中的實例

          同樣的,我們也可以再向容器中注冊一個Pet組件,如下所示。

          package com.meimeixia.boot.config;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.bean.User;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;

          /**
           * @author liayun
           * @create 2021-04-23 19:42
           *。
           */
          @Configuration // 告訴Spring Boot這是一個配置類 == 配置文件
          public class MyConfig {

              @Bean // @Bean注解是給容器中添加組件的。添加什么組件呢?以方法名作為組件的id,返回類型就是組件類型,返回的值就是組件在容器中的實例
              public User user01() {
                  User zhangsan = new User("zhangsan", 18);
                  return zhangsan;
              }

              @Bean
              public Pet tomcatPet() {
                  return new Pet("tomcat");
              }

          }

          這時,我們?nèi)萜髦芯蜁袃蓚€組件了,那怎么來驗證容器中有兩個組件呢?很簡單,來到咱們的主程序類中,因為在主程序類中直接給我們返回了容器,所以我們就可以從容器中來獲取組件了。當(dāng)然了,我們也可以先不獲取,而是先將容器中所有組件的名字全部打印出來,看打印出的這些名字里面有沒有我們想要的兩個組件的名字。

          package com.meimeixia.boot;

          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.SpringBootConfiguration;
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
          import org.springframework.context.ConfigurableApplicationContext;
          import org.springframework.context.annotation.ComponentScan;

          /**
           * 主程序類,也叫主配置類
           * @author liayun
           * @create 2021-04-19 4:02
           */
          //@SpringBootApplication
          @SpringBootConfiguration
          @EnableAutoConfiguration
          @ComponentScan("com.meimeixia.boot")
          public class MainApplication {

              public static void main(String[] args) {
                  // 1. 返回IoC容器,IoC容器里面就包含了當(dāng)前應(yīng)用的所有組件
                  ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 這是固定寫法喲
                  // 2. 我們可以來查看下IoC容器里面所有的組件,只要能查找到某一個組件,就說明這個組件是能工作的,至于怎么工作,這就是我們后來要闡述的原理了
                  String[] names = run.getBeanDefinitionNames(); // 獲取所有組件定義的名字
                  for (String name : names) {
                      System.out.println(name);
                  }
                  
                  // 3. 從容器中獲取組件

              }

          }

          我們在IDEA控制臺中以user01關(guān)鍵字來搜一下,發(fā)現(xiàn)確實能搜到我們注冊到容器中的組件,如下圖所示,而且還可以看到組件的名字默認(rèn)就是方法名。

          當(dāng)然,你不想讓方法名作為組件名字,而是想給它一個自定義的名字,也是可以的喲!要知道,我們在Spring XML配置文件里面也是可以使用<bean>標(biāo)簽為要注冊的組件起一個自定義的名字的。例如,想要為注冊的Pet組件起名為tom,我們只需要將tomcatPet方法上的@Bean注解修改為@Bean(“tom”)即可,如下所示。

          package com.meimeixia.boot.config;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.bean.User;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;

          /**
           * @author liayun
           * @create 2021-04-23 19:42
           *。
           */
          @Configuration // 告訴Spring Boot這是一個配置類 == 配置文件
          public class MyConfig {

              @Bean // @Bean注解是給容器中添加組件的。添加什么組件呢?以方法名作為組件的id,返回類型就是組件類型,返回的值就是組件在容器中的實例
              public User user01() {
                  User zhangsan = new User("zhangsan", 18);
                  return zhangsan;
              }

              @Bean("tom")
              public Pet tomcatPet() {
                  return new Pet("tomcat");
              }

          }

          這樣,要注冊的Pet組件的名字就不再是方法名,而是我們自己定義的名字了。這時,不妨再來重新運行一下主程序類,然后我們再來IDEA控制臺中搜索一下,相信你很快就能找到名字為tom的組件了,如下圖所示。

          而且,我們給容器中注冊的這兩個組件,它們默認(rèn)都是單實例的喲??,也就是說,我們無論從容器中獲取多少次,獲取的都是同一個實例。這兒,不妨我們來驗證一下吧!即我從容器中多次獲取名字為tom的寵物類型的組件,看看它們是不是同一個實例。

          package com.meimeixia.boot;

          import com.meimeixia.boot.bean.Pet;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.SpringBootConfiguration;
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
          import org.springframework.context.ConfigurableApplicationContext;
          import org.springframework.context.annotation.ComponentScan;

          /**
           * 主程序類,也叫主配置類
           * @author liayun
           * @create 2021-04-19 4:02
           */
          //@SpringBootApplication
          @SpringBootConfiguration
          @EnableAutoConfiguration
          @ComponentScan("com.meimeixia.boot")
          public class MainApplication {

              public static void main(String[] args) {
                  // 1. 返回IoC容器,IoC容器里面就包含了當(dāng)前應(yīng)用的所有組件
                  ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 這是固定寫法喲
                  // 2. 我們可以來查看下IoC容器里面所有的組件,只要能查找到某一個組件,就說明這個組件是能工作的,至于怎么工作,這就是我們后來要闡述的原理了
                  String[] names = run.getBeanDefinitionNames(); // 獲取所有組件定義的名字
                  for (String name : names) {
                      System.out.println(name);
                  }
                  
                  // 3. 從容器中獲取組件
                  Pet tom01 = run.getBean("tom", Pet.class);
                  Pet tom02 = run.getBean("tom", Pet.class);
                  System.out.println("組件是否為單實例:" + (tom01 == tom02));
              }

          }

          再次重新運行主程序類,發(fā)現(xiàn)IDEA控制臺打印結(jié)果如下。

          這已然說明了,我們注冊的組件默認(rèn)就是單實例的。也就是說,你就算獲取無限次組件,獲取到的也是一樣的。

          至此,我們來總結(jié)一下,給一個類上標(biāo)注@Configuration注解,就是為了告訴Spring Boot該類是一個配置類,然后,我們就可以在該配置類里面使用@Bean注解標(biāo)注在方法上向容器中注冊組件了,而且,注冊的組件默認(rèn)還是單實例的喲

          值得注意的是@Configuration注解標(biāo)注的類本身也是一個組件喲,也就是說配置類本身也是容器中的一個組件。不妨來驗證一下,即我們從容器中能不能獲取到配置類。

          package com.meimeixia.boot;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.config.MyConfig;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.SpringBootConfiguration;
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
          import org.springframework.context.ConfigurableApplicationContext;
          import org.springframework.context.annotation.ComponentScan;

          /**
           * 主程序類,也叫主配置類
           * @author liayun
           * @create 2021-04-19 4:02
           */
          //@SpringBootApplication
          @SpringBootConfiguration
          @EnableAutoConfiguration
          @ComponentScan("com.meimeixia.boot")
          public class MainApplication {

              public static void main(String[] args) {
                  // 1. 返回IoC容器,IoC容器里面就包含了當(dāng)前應(yīng)用的所有組件
                  ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 這是固定寫法喲
                  // 2. 我們可以來查看下IoC容器里面所有的組件,只要能查找到某一個組件,就說明這個組件是能工作的,至于怎么工作,這就是我們后來要闡述的原理了
                  String[] names = run.getBeanDefinitionNames(); // 獲取所有組件定義的名字
                  for (String name : names) {
                      System.out.println(name);
                  }
                  
                  // 3. 從容器中獲取組件
                  Pet tom01 = run.getBean("tom", Pet.class);
                  Pet tom02 = run.getBean("tom", Pet.class);
                  System.out.println("組件是否為單實例:" + (tom01 == tom02));

                  // 配置類打印:com.meimeixia.boot.config.MyConfig$$EnhancerBySpringCGLIB$$4559f04d@49096b06
                  MyConfig bean = run.getBean(MyConfig.class);
                  System.out.println(bean);
              }

          }

          再次重新運行主程序類,發(fā)現(xiàn)IDEA控制臺打印結(jié)果如下。

          可以看到能打印出MyConfig配置類這個組件,所以,我們才說配置類本身也是組件。下面,我可要說一個@Configuration注解最大的特性了,大家可一定要睜大眼睛看好喲~

          Spring Boot 2.0這個版本以后,@Configuration注解里面多了一個屬性,我們不妨進(jìn)入到@Configuration注解的源碼里面去看一看,如下圖所示。

          可以看到,確實多了一個叫proxyBeanMethods的屬性,而且其默認(rèn)值還是true。注意,該屬性是Spring Boot基于Spring 5.2而來的喲~

          也就是說,現(xiàn)在在我們的MyConfig配置類上面標(biāo)注的@Configuration注解,默認(rèn)其里面的proxyBeanMethods屬性是為true的,那proxyBeanMethods屬性有什么作用呢?它可有大作用了,而且它也是Spring Boot 2.0Spring Boot 1.0的不同之處。proxyBeanMethods翻譯過來的話,應(yīng)該就是代理bean的方法的意思了,這說的啥啊?要不我現(xiàn)在先來提出這樣一個大膽的猜想吧!就是拿到配置類這個組件之后,我們不妨來多次調(diào)用其里面的方法,例如user01方法,這時,會不會得到的是不一樣的對象呢?

          package com.meimeixia.boot;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.bean.User;
          import com.meimeixia.boot.config.MyConfig;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.SpringBootConfiguration;
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
          import org.springframework.context.ConfigurableApplicationContext;
          import org.springframework.context.annotation.ComponentScan;

          /**
           * 主程序類,也叫主配置類
           * @author liayun
           * @create 2021-04-19 4:02
           */
          //@SpringBootApplication
          @SpringBootConfiguration
          @EnableAutoConfiguration
          @ComponentScan("com.meimeixia.boot")
          public class MainApplication {

              public static void main(String[] args) {
                  // 1. 返回IoC容器,IoC容器里面就包含了當(dāng)前應(yīng)用的所有組件
                  ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 這是固定寫法喲
                  // 2. 我們可以來查看下IoC容器里面所有的組件,只要能查找到某一個組件,就說明這個組件是能工作的,至于怎么工作,這就是我們后來要闡述的原理了
                  String[] names = run.getBeanDefinitionNames(); // 獲取所有組件定義的名字
                  for (String name : names) {
                      System.out.println(name);
                  }
                  
                  // 3. 從容器中獲取組件
                  Pet tom01 = run.getBean("tom", Pet.class);
                  Pet tom02 = run.getBean("tom", Pet.class);
                  System.out.println("組件是否為單實例:" + (tom01 == tom02));

                  // 配置類打印:com.meimeixia.boot.config.MyConfig$$EnhancerBySpringCGLIB$$4559f04d@49096b06
                  MyConfig bean = run.getBean(MyConfig.class);
                  System.out.println(bean);

                  User user = bean.user01();
                  User user1 = bean.user01();
                  System.out.println("(user == user1) = " + (user == user1));
              }

          }

          我們知道配置類里面的user01方法就是給容器中注冊組件的,因為該方法上面標(biāo)注了@Bean注解。而現(xiàn)在我在配置類外面把user01這個方法多調(diào)了兩遍,那么該方法返回的User對象是從容器中拿的嗎?還是說這尼瑪就是一個普通方法的調(diào)用。不管了,咱們就直接運行主程序類來驗證一下,發(fā)現(xiàn)IDEA控制臺打印的結(jié)果如下圖所示。

          也就是說,配置類里面組件注冊的方法,無論你在外面調(diào)多少遍,獲取到的都是容器中的單實例對象。

          至此,我們再來總結(jié)一下,我們在外部無論對配置類中的組件注冊方法調(diào)用多少次,獲取到的都是之前注冊到容器中的單實例對象。所以,在IDEA控制臺這一塊,我們才能看到兩次調(diào)用user01方法獲取到的兩個User對象是同一個對象。

          那么其原因何在呢?原因就在@Configuration注解里面的proxyBeanMethods屬性。我們知道配置類本身也是組件,從IDEA控制臺打印出的結(jié)果中我們還能知道它并不是一個普通對象,而是一個被Spring CGLIB增強了的代理對象,所以,可以這樣說,我們獲取到的配置類組件本身就是一個代理對象。當(dāng)我們在外部通過該代理對象來調(diào)用其方法時,那么Spring Boot里面的默認(rèn)邏輯就是這樣子的,即Spring Boot默認(rèn)會檢查容器中是否有該方法已經(jīng)返回了的組件,若有則不會新創(chuàng),而是直接拿,簡簡單單一句話,就是要保持組件單實例;若沒有則再來調(diào)用該方法創(chuàng)建一個新的,總之,Spring Boot總會檢查方法返回的組件是否在容器中存在。當(dāng)然了,這一切的前提是@Configuration注解里面的proxyBeanMethods屬性的值為true(@Configuration(proxyBeanMethods = true)),即在配置類中的方法被代理的情況下(proxyBeanMethods翻譯過來就是代理bean的方法嘛),我們才能看到上述這種現(xiàn)象。

          但是,如果我們把@Configuration注解里面的proxyBeanMethods屬性的值置為false,即@Configuration(proxyBeanMethods = false),那么又是一種什么現(xiàn)象呢?我們不妨重新運行一下主程序類,給大家看看此時的效果。

          可以看到,此時我們從容器中拿到的MyConfig類型的組件就不再是代理對象了,而是一個普普通通的對象,而且,還能看到兩次調(diào)用user01方法獲取到的兩個User對象不再是同一個對象了。

          以上就是我們要說的proxyBeanMethods屬性的作用。而且,該屬性還另外引申出了這樣一個概念,Spring Boot在底層對@Configuration注解有兩種配置,它們分別是:

          • Full:即@Configuration(proxyBeanMethods = true),一般稱為全配置

          • Lite:即@Configuration(proxyBeanMethods = false),一般稱為輕量級配置

          也就是說,以后我們想要給容器中添加組件的時候,不是會編寫一個配置類嘛,然后,如果@Configuration注解里面的proxyBeanMethods屬性的值為true,那么配置類里面每一個向容器中注冊組件的方法在外面都能隨便調(diào)用,而且該方法都會去容器中找組件,這就是所謂的Full模式;如果@Configuration注解里面的proxyBeanMethods屬性的值為false,那么配置類組件本身在容器中就再也不會被保存為代理對象了,這樣,當(dāng)你在外面無限次調(diào)用其中的方法時,你的每一次方法調(diào)用就都會產(chǎn)生一個新的對象了,這就是所謂的Lite模式。

          說了這么多,那么它適用于什么場景呢?我就直說了吧!組件依賴必須使用默認(rèn)的Full模式,其他則默認(rèn)使用Lite模式。還是舉一個例子來說吧,假設(shè)用戶要養(yǎng)一個寵物,那么在User類中是不是得加上一個Pet類型的屬性啊?

          package com.meimeixia.boot.bean;

          /**
           * @author liayun
           * @create 2021-04-23 19:14
           *
           * 用戶
           */
          public class User {

              private String name;
              private Integer age;

              private Pet pet;

              public Pet getPet() {
                  return pet;
              }

              public void setPet(Pet pet) {
                  this.pet = pet;
              }

              public User() {

              }

              public User(String name, Integer age) {
                  this.name = name;
                  this.age = age;
              }

              public String getName() {
                  return name;
              }

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

              public Integer getAge() {
                  return age;
              }

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

              @Override
              public String toString() {
                  return "User{" +
                          "name='" + name + '\'' +
                          ", age=" + age +
                          ", pet=" + pet +
                          '
          }';
              }

          }

          可以看到,我們又重寫了User類的toString方法。此時,相當(dāng)于我們現(xiàn)在給容器中注冊了一個User類型的組件,但這個組件還想要用之前容器中注冊的寵物類型的組件。

          我們不妨先使用一下默認(rèn)的Full模式,即將@Configuration注解里面的proxyBeanMethods屬性的值置為true,在這種模式下,用戶想要養(yǎng)寵物,是不是就得這樣啊?

          package com.meimeixia.boot.config;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.bean.User;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;

          /**
           * @author liayun
           * @create 2021-04-23 19:42
           *
           */
          @Configuration(proxyBeanMethods = true) // 告訴Spring Boot這是一個配置類 == 配置文件
          public class MyConfig {

              @Bean // @Bean注解是給容器中添加組件的。添加什么組件呢?以方法名作為組件的id,返回類型就是組件類型,返回的值就是組件在容器中的實例
              public User user01() {
                  User zhangsan = new User("zhangsan", 18);
                  // User類型的組件依賴了Pet類型的組件
                  zhangsan.setPet(tomcatPet());
                  return zhangsan;
              }

              @Bean("tom")
              public Pet tomcatPet() {
                  return new Pet("tomcat");
              }

          }

          從上可以看到,用戶養(yǎng)的寵物就是容器中的寵物,這說明了User類型的組件依賴了Pet類型的組件。而且,在默認(rèn)的Full模式下,這種組件依賴是成立的,對此,我們不妨來確認(rèn)一下。

          package com.meimeixia.boot;

          import com.meimeixia.boot.bean.Pet;
          import com.meimeixia.boot.bean.User;
          import com.meimeixia.boot.config.MyConfig;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.SpringBootConfiguration;
          import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
          import org.springframework.context.ConfigurableApplicationContext;
          import org.springframework.context.annotation.ComponentScan;

          /**
           * 主程序類,也叫主配置類
           * @author liayun
           * @create 2021-04-19 4:02
           */
          //@SpringBootApplication
          @SpringBootConfiguration
          @EnableAutoConfiguration
          @ComponentScan("com.meimeixia.boot")
          public class MainApplication {

              public static void main(String[] args) {
                  // 1. 返回IoC容器,IoC容器里面就包含了當(dāng)前應(yīng)用的所有組件
                  ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 這是固定寫法喲
                  // 2. 我們可以來查看下IoC容器里面所有的組件,只要能查找到某一個組件,就說明這個組件是能工作的,至于怎么工作,這就是我們后來要闡述的原理了
                  String[] names = run.getBeanDefinitionNames(); // 獲取所有組件定義的名字
                  for (String name : names) {
                      System.out.println(name);
                  }
                  
                  // 3. 從容器中獲取組件
                  Pet tom01 = run.getBean("tom", Pet.class);
                  Pet tom02 = run.getBean("tom", Pet.class);
                  System.out.println("組件是否為單實例:" + (tom01 == tom02));

                  // 配置類打印:com.meimeixia.boot.config.MyConfig$$EnhancerBySpringCGLIB$$4559f04d@49096b06
                  MyConfig bean = run.getBean(MyConfig.class);
                  System.out.println(bean);

                  User user = bean.user01();
                  User user1 = bean.user01();
                  System.out.println("(user == user1) = " + (user == user1));

                  User user01 = run.getBean("user01", User.class);
                  Pet tom = run.getBean("tom", Pet.class);
                  System.out.println("用戶的寵物:" + (user01.getPet() == tom));
              }

          }

          再次重新運行主程序類,發(fā)現(xiàn)IDEA控制臺打印出了如下結(jié)果。

          可以看到,用戶養(yǎng)的寵物就是容器中的寵物。你現(xiàn)在該知道,使用默認(rèn)的Full模式,就能很方便地來解決組件依賴的問題了吧!

          但是,如果我們將@Configuration注解里面的proxyBeanMethods屬性的值置為false,那么會導(dǎo)致什么現(xiàn)象出現(xiàn)呢?艸,你會發(fā)現(xiàn)連編譯都通不過去,在調(diào)用tomcatPet方法時,發(fā)現(xiàn)它下面有一個紅色的波浪線,如下圖所示。

          代碼編譯都通不過,接下來就不用測試了吧!

          以上就是我們Spring Boot 2.0最大的一個更新,即我們可以將配置類編寫為輕量級模式和全模式這兩種配置模式。

          那么,將配置類編寫為輕量級模式有什么優(yōu)點呢?優(yōu)點就是Spring Boot不會來檢查組件注冊的方法(例如user01方法)返回的東東在容器中有沒有,相當(dāng)于就跳過了檢查,這樣,我們整個Spring Boot應(yīng)用啟動并運行起來就非常快了。而如果是將配置類編寫為全模式,那么外界對它里面的方法的每一次調(diào)用,Spring Boot都會檢查容器中是不是有了該方法已經(jīng)返回了的組件。

          雖然Spring Boot給我們帶來了Full和Lite這兩種配置模式,但是在Spring Boot的最佳實踐中,我們推薦的做法是這樣子的——如果我們只是向容器中單單注冊組件,而且也不存在組件依賴,那么一般使用Lite模式,因為這樣的話,我們Spring Boot應(yīng)用整個的啟動速度就會非常快,加載起來也會非常快喲;如果存在組件依賴,那么一般使用Full模式,因為這樣能保證某一個組件它所依賴的組件就是容器中的組件。

          這就是Spring Boot 2.0里面,@Configuration注解結(jié)合@Bean注解給容器中添加組件的使用方法,而且我們也看到了這跟以前是有大大的不同喲??,大家未來會在Spring Boot底層見到非常多這樣的寫法。



          版權(quán)聲明本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明

          本文鏈接

          https://blog.csdn.net/yerenyuan_pku/article/details/116201120





          粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

          ??????

          ??長按上方微信二維碼 2 秒


          感謝點贊支持下哈 

          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本色天堂 | 青青草男人天堂 | 久久亚洲一区女同性恋中文字幕 | 懂色AV色吟AV夜夜嗨 | 免费公开成人视频 |