Profile

来源:https://www.cnblogs.com/evanlin/archive/2022/03/28/16069665.html
-Advertisement-
Play Games

總有那麼一些時候,我們希望Spring容器能夠根據我們提供的條件決定哪些Bean需要創建,哪些Bean不需要創建。提供的條件不同,Spring容器創建的Bean也不同。創建的Bean不同,軟體實現的功能自然也有所差別。也就是說,我們希望在某些應用場景下無需修改代碼或重新構建項目,只需簡單修改一下條件 ...


總有那麼一些時候,我們希望Spring容器能夠根據我們提供的條件決定哪些Bean需要創建,哪些Bean不需要創建。提供的條件不同,Spring容器創建的Bean也不同。創建的Bean不同,軟體實現的功能自然也有所差別。也就是說,我們希望在某些應用場景下無需修改代碼或重新構建項目,只需簡單修改一下條件就能達到改變軟體功能的目的。

於是,Profile出現了。能讓我們向Spring容器提供一些配置信息,告訴Spring容器兩件事情:
1.告訴Spring容器我們想要創建的Bean屬於哪個Profile
2.告訴Spring容器只需創建屬於某些Profile的Bean,無需創建屬於其它Profile的Bean

如此一來,Spring容器就能按照指定的Profile創建指定的Bean。指定的Profile不同,創建的Bean也不同。創建的Bean不同,軟體實現的功能自然也就不同。非常明顯,Profile就是專門用來條件化Bean的創建的。

問題在於,我們應該怎樣告訴Spring容器Bean是屬於哪個Profile的呢?

這就涉及@Profile註解了。@Profile註解有個value屬性,能夠指定Bean所屬的Profile。假如com.dream包現有這樣一些類:

 1 public interface Music {
 2 }
 3 
 4 public class ClassicMusic implements Music {
 5 }
 6 
 7 public class CountryMusic implements Music {
 8 }
 9 
10 public class Player {
11     private Music playingMusic = null;
12 
13     public Player(Music playingMusic) {
14         this.playingMusic = playingMusic;
15     }
16 }

則可使用@Profile註解這樣配置Bean:

 1 @Configuration
 2 public class AppConfig {
 3     @Bean(name = "classisMusic")
 4     @Profile(value = "classicProfile")
 5     public Music produceClassicMusic() {
 6         return new ClassicMusic();
 7     }
 8 
 9     @Bean(name = "countryMusic")
10     @Profile(value = "countryProfile")
11     public Music produceCountryMusic() {
12         return new CountryMusic();
13     }
14 
15     @Bean(name = "player")
16     public Player producePlayer(Music playingMusic) {
17         return new Player(playingMusic);
18     }
19 }

該配置類定義了三個方法,配置了三個Bean:
1.方法produceClassicMusic帶有 @Profile(value = "classicProfile") 註解。如果激活的是classicProfile,Spring容器就會調用這個方法創建ClassicMusic類型的Bean;否則不創建。
2.方法produceCountryMusic帶有 @Profile(value = "countryProfile") 註解。如果激活的是countryProfile,Spring容器就會調用這個方法創建CountryMusic類型的Bean;否則不創建。
3.方法producePlayer沒帶@Profile註解,不屬於任何Profile。不管激活的是哪些Profile,Spring容器都會調用這個方法創建Player類型的Bean

於是我們知道了,Bean所屬的Profile是由@Profile註解標註的。接下來我們需要做的,就是告訴Spring容器哪些Profile是激活的。而這,還得仰賴Spring提供的Environment介面。如下所示:

1 try (var context = new AnnotationConfigApplicationContext()) {
2     context.getEnvironment().setActiveProfiles("classicProfile");
3     context.register(AppConfig.class);
4     context.refresh();
5 }

這段代碼做了這些事情:
1.創建AnnotationConfigApplicationContext類型的Spring容器。
2.獲取Spring容器里的Environment介面之後調用setActiveProfiles方法激活Profile
3.把Java配置類註冊給Spring容器。
4.刷新Spring容器,完成Bean的創建。

毫無疑問,問題的關鍵在於第二步。Environment介面提供了setActiveProfiles方法,用於激活指定的Profile。它的簽名如下:

1 public void setActiveProfiles(String... profiles)

它的參數是 String... 類型的,能夠同時指定多個激活的Profile。而我們的這段代碼只激活了classicProfile,告訴Spring容器只創建ClassicMusic類型的Bean,不創建CountryMusic類型的Bean。當然,Player類型的Bean總會被創建,因為它不屬於任何Profile

值得關註的是,除了激活Profile,我們也能指定預設的Profile。這樣,如果指定了激活的Profile,Spring容器就會使用激活的Profile創建Bean;如果沒有指定激活的Profile,Spring容器就會使用預設的Profile創建Bean。預設的Profile能由Environment介面的setDefaultProfiles方法指定。它的簽名如下:

1 public void setDefaultProfiles(String... profiles)

它的參數是 String... 類型的,同樣支持同時指定多個預設的Profile,這和setActiveProfiles方法是一樣的,不再贅敘。

於是我們知道了,預設或激活的Profile都可調用Environment介面指定。而在Web開發中,我們並不需要直接調用Environment介面,只要使用spring.profiles.default屬性指定預設的Profile,使用spring.profiles.active屬性指定激活的Profile就行。預設或激活的Profile可以同時指定多個,之間用逗號隔開即可。

這樣,Spring容器就能用spring.profiles.default屬性的值調用Environment介面指定預設的Profile;使用pring.profiles.active屬性的值調用Environment介面指定激活的Profile。以下是spring.profiles.default屬性和spring.profiles.active屬性可以指定的地方:
1.Servlet初始化參數
2.Servlet上下文初始化參數
3.JNDI環境變數
4.JVM系統屬性(也就是JVM的命令行參數)
5.操作系統環境變數

比如,我們可在部署描述文件web.xml里指定Servlet初始化參數和Servlet上下文初始化參數,這樣指定預設的Profile:

 1 <context-param>
 2   <param-name>contextConfigLocation</param-name>
 3   <param-value>/WEB-INF/config/root-config.xml</param-value>
 4 </context-param>
 5 <context-param>
 6   <param-name>spring.profiles.default</param-name>
 7   <param-value>classicProfile</param-value>
 8 </context-param>
 9 <listener>
10   <listener-class>
11     org.springframework.web.context.ContextLoaderListener
12   </listener-class>
13 </listener>
14 
15 <servlet>
16   <servlet-name>dispatcherServlet</servlet-name>
17   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
18   <init-param>
19     <param-name>contextConfigLocation</param-name>
20     <param-value>/WEB-INF/config/servlet-config.xml</param-value>
21   </init-param>
22   <init-param>
23     <param-name>spring.profiles.default</param-name>
24     <param-value>classicProfile</param-value>
25   </init-param>
26   <load-on-startup>1</load-on-startup>
27 </servlet>

在Servlet初始化參數里,我們把classicProfile指給spring.profiles.default屬性,以使根容器知道預設的Profile是classicProfile,進而只創建屬於classicProfile的Bean;在Servlet上下文初始化參數里,我們把classicProfile指給spring.profiles.default屬性,以使Servlet容器知道預設的Profile是classicProfile,進而只創建屬於classicProfile的Bean

到了運行Web應用程式的時候,如果我們想要創建屬於countryProfile的Bean,只需通過JVM命令行參數之類的,把countryProfile指給spring.profiles.active屬性就行。

還有,@Profile註解除了可以像上面的示例那樣加到配置方法之外,也可以加到配置類上。如下所示:

 1 @Configuration
 2 @Profile(value = "classicProfile")
 3 public class AppConfigClassic {
 4     @Bean(name = "classisMusic")
 5     public Music produceClassicMusic() {
 6         return new ClassicMusic();
 7     }
 8 }
 9 
10 @Configuration
11 @Profile(value = "countryProfile")
12 public class AppConfigCountry {
13     @Bean(name = "countryMusic")
14     public Music produceCountryMusic() {
15         return new CountryMusic();
16     }
17 }
18 
19 @Configuration
20 public class AppConfig {
21     @Bean(name = "player")
22     public Player producePlayer(Music playingMusic) {
23         return new Player(playingMusic);
24     }
25 }

這段代碼定義了三個配置類:
1.配置類AppConfigClassic帶有 @Profile(value = "classicProfile") 註解。只有激活了classicProfile,Spring容器才會創建該配置類里的Bean;否則不創建。
2.配置類AppConfigCountry帶有 @Profile(value = "countryProfile") 註解。只有激活了countryProfile,Spring容器才會創建該配置類里的Bean;否則不創建。
3.配置類AppConfig沒帶@Profile註解。不管激活了哪些Profile,Spring容器都會創建該配置類里的Bean

當然,XML配置文件也支持Profile。如果採用XML配置文件的話,可用<beans>元素這樣配置:

 1 <beans /* 省略命名空間和XSD模式文件聲明 */>
 2     <beans profile="classicProfile">
 3         <bean id="classicMusic" class="com.dream.ClassicMusic">
 4             <property name="musicName" value="Classic Music" />
 5         </bean>
 6     </beans>
 7     <beans profile="countryProfile">
 8         <bean id="countryMusic" class="com.dream.CountryMusic">
 9             <property name="musicName" value="Country Music" />
10         </bean>
11     </beans>
12 
13     <bean id="player" class="com.dream.Player" autowire="byType" />
14 </beans>

也可使用多個XML配置文件這樣配置:

 1 <beans profile="classicProfile" /* 省略命名空間和XSD模式文件聲明 */>
 2     <bean id="classicMusic" class="com.dream.ClassicMusic">
 3         <property name="musicName" value="Classic Music" />
 4     </bean>
 5 </beans>
 6 
 7 <beans profile="countryProfile" /* 省略命名空間和XSD模式文件聲明 */>
 8     <bean id="countryMusic" class="com.dream.CountryMusic">
 9         <property name="musicName" value="Country Music" />
10     </bean>
11 </beans>
12 
13 <beans /* 省略命名空間和XSD模式文件聲明 */>
14     <bean id="player" class="com.dream.Player" autowire="byType" />
15 </beans>

至此,關於Profile的介紹也就告一段落了。下章,我們將會開始介紹Condition以及藏在Profile背後的秘密。歡迎大家繼續閱讀,謝謝大家!

返回目錄    下載代碼


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本期,我們將為大家帶來HDF驅動框架中USB DDK的解析與指導。 ...
  • 一、藍牙模式HID與BLE 當掃碼槍與手機連接時,通常採用的是藍牙HID(Human Interface Device)模式。本質上是一個把掃碼槍作為一個硬體鍵盤,按照鍵盤協議把掃碼後的結果逐個輸入到對應的控制項上。 優點:無需開發集成,配對就可以立即作為鍵盤輸入使用。可以使用輸入框等組件直接接收掃碼 ...
  • 華為 AppLinking 服務,是一項支持通過跨平臺使用的深度鏈接,可以支持通過鏈接拉起指定頁面,並且傳遞 DeepLink 數據。更加重要的是,AppLinking 支持在應用未安裝的情況下,自動拉起應用市場的應用詳情頁,可以很好的覆蓋應用未安裝的情況。 本帖主要介紹在 Android 項目中, ...
  • 在移動端閱讀資訊時,人們對高解析度、高質量的圖像要求越來越高。但受限於網路流量、存儲、圖片源等諸多因素,用戶無法便捷獲得高質量圖片。移動端顯示設備的高解析度圖片獲得問題亟待解決。不久前,HMS Core新聞Demo App針對新聞垂域的閱讀體驗做了一系列更新優化,其中就包括圖像超分。 圖像超解析度( ...
  • 3月15日新增“1860+1194”,全國進入了抗疫關鍵時期。響應政策多地採取了社會面清零策略。 3月14日零點,深圳按下了暫停鍵。 應疫情防控要求,深圳全市暫停生產經營活動,嚴格實行7天封閉式管理。消息一經發佈,3.13日當晚,全深圳打工人連夜回公司取電腦。衝上了熱搜。“上班帶棉被,下班帶電腦”深 ...
  • 一、什麼是對象? 對象指一個具體的事物,泛指的不算對象,對像是一組無序的相關屬性和方法的集合;屬性是特征常用名詞來表示,方法是行為常用動詞來表示。 二、為什麼需要對象? 當我們保存一個值時,可以使用變數,保存多個值時,可以使用數組;當我們需要保存很多完整、複雜的信息時,我們就會需要對象。 三、創建對 ...
  • 定義和用法 forEach() 調用數組的每個元素,並將元素傳遞給回調函數。 註意: forEach() 對於空數組是不會執行回調函數的。 用法: array.forEach(function(currentValue, index, arr), thisValue) 1==> currentVal ...
  • FizzBu​​zz 是一道很有意思的題目。我們來看看題目: 如果遇見了 3 的倍數要說 Fizz,5 的倍數就說 Buzz,如果即是 3 的倍數又是 5 的倍數就說 FizzBuzz。 如果是在一些編程語言中,這是一道比較初級的題目,當然,稍微轉換一下,我們就可以把它轉換成一道有關 CSS 選擇器 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...