<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
@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>
現在Spring Boot 已經不寫上面的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): 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * Lite(proxyBeanMethods = false): 在容器中不會保留代理物件,外部多次呼叫這些元件時,每次呼叫都會產生一個新的物件 * 用於解決元件依賴場景 */ @Configuration(proxyBeanMethods = true) //告訴SpringBoot 這是一個設定類 == 以前的組態檔 public class MyConfig { /** * 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * @return */ @Bean //給容器中新增元件,以方法名作為主鍵id,返回型別就是元件型別,返回值就是元件在容器中的範例 public User user01(){ return new User("dragon",18); } @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)代理物件呼叫方法, 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時,外部無論對設定類中的元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件。
(2)Lite模式(proxyBeanMethods = false): 為false時,在容器中不會保留代理物件,外部多次呼叫這些元件時,每次呼叫都會產生一個新的物件。
這兩種模式的存在主要用於解決元件依賴場景。
1和2 兩點特性上面的例子中都有體現, 接下來重點實踐第三點特性:
實踐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): 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * Lite模式(proxyBeanMethods = false): 在容器中不會保留代理物件,外部多次呼叫這些元件時,每次呼叫都會產生一個新的物件 * 用於解決元件依賴場景 */ @Configuration(proxyBeanMethods = true) //告訴SpringBoot 這是一個設定類 == 以前的組態檔 public class MyConfig { /** * 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * @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)代理物件呼叫方法, 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)); } }
執行結果:
可以看出,Full模式(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): 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * Lite模式(proxyBeanMethods = false): 在容器中不會保留代理物件,外部多次呼叫這些元件時,每次呼叫都會產生一個新的物件 * 用於解決元件依賴場景 */ @Configuration(proxyBeanMethods = false) //告訴SpringBoot 這是一個設定類 == 以前的組態檔 public class MyConfig { /** * 外部無論對設定類中的這個元件註冊方法呼叫多少次,獲取的都是之前註冊容器中的單範例物件 * @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 新增的一個很重要的特性。
最佳實戰:如果只是向容器中增加元件,別的地方也不會呼叫這個元件,我們可以將其調為false 模式,這樣Spring Boot 啟動起來非常快,載入起來也非常快。 如果別的地方明顯要用,要依賴,我們就把其調成true,保證依賴的元件就是容器中的元件。
注: 前面的例子中,在設定類中用到@Been 註解來指定元件, 其實Spring Boot 底層還用到了其他一些以前常用的註解來指定元件,包括@Component、@Controller、@Service、@Repository。這些類似於@Been 原理,也是用於向容器中註冊元件。
除此之外,底層還用到@ComponentScan 註解來說明容器的包掃描,還有@Import 和@Conditional 來向容器新增元件。很多註解是以前常用的,接下來主要說明@Import 和@Conditional 註解。
首先,從@Import 註解類中可以看到該註解的定義,以及知道其屬性是一個Class型別的陣列,說明這個註解的作用是向容器中匯入一批元件:
接下來,實踐一下:
首先在設定類上加入@Import 註解,並向容器中匯入兩個元件,一個是自己定義的類,一個是從第三方Jar 包中任意的一個類:
主類加入如下測試:
執行結果:
結果說明:
“com.menergy.boot.bean.User” 是通過@Import 匯入的元件。(預設的元件名稱是全類名)
“user01” 是之前用@Bean 方法新增進去的
“org.apache.logging.log4j.util.StringBuilders@4482469c” 也是通過@Import 匯入的元件。
@Conditional 是條件裝配:當滿足@Conditional指定的條件時, 才向容器中注入元件。
在全域性Jar包中搜尋@Conditional 類:雙擊Shift鍵,選擇Classes,輸入@Conditional搜尋。
注:如果調不出這個視窗,請參考:IDEA 操作與設定筆記
https://www.jb51.net/article/208232.htm
開啟Conditional 類後,“Ctrl + H” 鍵調出這個類的繼承樹:
注:如果快捷鍵失效,請確定如下快捷鍵設定:
從前面的@Conditional 的繼承樹可以看出,@Conditional 有非常多的派生註解,每個註解都代表不同的功能,從派生註解的註解名稱可以大概知道其功能用意,例如@ConditionalOnBean 註解代表當容器中存在某個Bean時才幹某些事情, @ConditionalOnMissingBean 註解代表當容器中不存在某個Bean時才幹某些事情。
接下來,以@ConditionalOnBean 為例,進行實踐:
到此這篇關於Spring Boot 底層原理基礎的文章就介紹到這了,更多相關Spring Boot 底層原理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45