日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

bean注入属性_摆脱困境:将属性值注入配置Bean

發(fā)布時(shí)間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bean注入属性_摆脱困境:将属性值注入配置Bean 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

bean注入屬性

Spring Framework對(duì)將從屬性文件中找到的屬性值注入到bean或@Configuration類(lèi)中提供了很好的支持。 但是,如果將單個(gè)屬性值注入這些類(lèi)中,則會(huì)遇到一些問(wèn)題。

這篇博客文章指出了這些問(wèn)題,并描述了我們?nèi)绾谓鉀Q它們。

讓我們開(kāi)始吧。

如果使用Spring Boot,則應(yīng)使用其Typesafe配置屬性。 您可以從以下網(wǎng)頁(yè)獲取有關(guān)此的更多信息:

  • Spring Boot參考手冊(cè)的23.7節(jié)Typesafe配置屬性
  • @EnableConfigurationProperties批注的Javadoc
  • @ConfigurationProperties批注的Javadoc
  • 在Spring Boot中使用@ConfigurationProperties

很簡(jiǎn)單,但并非沒(méi)有問(wèn)題

如果將單個(gè)屬性值注入到我們的bean類(lèi)中,我們將面臨以下問(wèn)題:

1.注入多個(gè)屬性值很麻煩

如果我們通過(guò)使用@Value批注注入單個(gè)屬性值,或者通過(guò)使用Environment對(duì)象來(lái)獲取屬性值,則注入多個(gè)屬性值會(huì)很麻煩。

假設(shè)我們必須向UrlBuilder對(duì)象注入一些屬性值。 該對(duì)象需要三個(gè)屬性值:

  • 服務(wù)器的主機(jī)( app.server.host )
  • 服務(wù)器監(jiān)聽(tīng)的端口( app.server.port )
  • 使用的協(xié)議( app.server.protocol )

當(dāng)UrlBuilder對(duì)象構(gòu)建用于訪(fǎng)問(wèn)Web應(yīng)用程序不同功能的URL地址時(shí),將使用這些屬性值。

如果我們使用構(gòu)造函數(shù)注入和@Value注釋注入這些屬性值,則UrlBuilder類(lèi)的源代碼如下所示:

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;@Component public class UrlBuilder {private final String host;private final String port;private final String protocol;@Autowiredpublic UrlBuilder(@Value("${app.server.protocol}") String protocol,@Value("${app.server.host}") String serverHost,@Value("${app.server.port}") int serverPort) {this.protocol = protocol.toLowercase();this.serverHost = serverHost;this.serverPort = serverPort;} }

補(bǔ)充閱讀:

  • @Value注釋的Javadoc

如果我們通過(guò)使用構(gòu)造函數(shù)注入和Environment類(lèi)注入這些屬性值,則UrlBuilder類(lèi)的源代碼如下所示:

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component;@Component public class UrlBuilder {private final String host;private final String port;private final String protocol;@Autowiredpublic UrlBuilder(Environment env) {this.protocol = env.getRequiredProperty("app.server.protocol").toLowercase();this.serverHost = env.getRequiredProperty("app.server.host");this.serverPort = env.getRequiredProperty("app.server.port", Integer.class);} }

補(bǔ)充閱讀:

  • 環(huán)境接口的Javadoc

我承認(rèn)這看起來(lái)還不錯(cuò)。 但是,當(dāng)所需屬性值的數(shù)量增加和/或我們的類(lèi)也具有其他依賴(lài)項(xiàng)時(shí),將所有這些屬性注入都是很麻煩的。

2.我們必須指定多個(gè)屬性名稱(chēng)(或記住使用常量)

如果我們將單個(gè)屬性值直接注入需要它們的bean中,并且多個(gè)bean(A和B)需要相同的屬性值,那么我們想到的第一件事就是在兩個(gè)bean類(lèi)中都指定屬性名稱(chēng):

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(@Value("${app.server.protocol}") String protocol) {this.protocol = protocol.toLowercase();} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(@Value("${app.server.protocol}") String protocol) {this.protocol = protocol.toLowercase();} }

這是一個(gè)問(wèn)題,因?yàn)?

  • 因?yàn)槲覀兪侨祟?lèi),所以我們會(huì)打錯(cuò)字 。 這不是一個(gè)大問(wèn)題,因?yàn)樵趩?dòng)應(yīng)用程序時(shí)我們會(huì)注意到它。 但是,它使我們放慢了速度。
  • 這使維護(hù)更加困難 。 如果更改屬性的名稱(chēng),則必須對(duì)使用該屬性的每個(gè)類(lèi)進(jìn)行此更改。
  • 我們可以通過(guò)將屬性名稱(chēng)移到常量類(lèi)來(lái)解決此問(wèn)題。 如果這樣做,我們的源代碼如下所示:

    public final PropertyNames {private PropertyNames() {}public static final String PROTOCOL = "${app.server.protocol}"; }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(@Value(PropertyNames.PROTOCOL) String protocol) {this.protocol = protocol.toLowercase();} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(@Value(PropertyNames.PROTOCOL) String protocol) {this.protocol = protocol.toLowercase();} }

    這可以解決維護(hù)問(wèn)題,但前提是所有開(kāi)發(fā)人員都記得要使用它。 我們當(dāng)然可以通過(guò)使用代碼審閱來(lái)強(qiáng)制執(zhí)行此操作,但這是審閱者必須記住要檢查的另一件事。

    3.添加驗(yàn)證邏輯成為問(wèn)題

    假設(shè)我們有兩個(gè)類(lèi)( A和B ),它們需要app.server.protocol屬性的值。 如果我們將此屬性值直接注入到A和B Bean中,并且想要確保該屬性的值為'http'或'https',則必須

  • 將驗(yàn)證邏輯添加到兩個(gè)bean類(lèi)中。
  • 將驗(yàn)證邏輯添加到實(shí)用程序類(lèi)中,并在需要驗(yàn)證是否給出了正確的協(xié)議時(shí)使用它。
  • 如果我們將驗(yàn)證邏輯添加到兩個(gè)bean類(lèi),則這些類(lèi)的源代碼如下所示:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(@Value("${app.server.protocol}") String protocol) {checkThatProtocolIsValid(protocol);this.protocol = protocol.toLowercase();}private void checkThatProtocolIsValid(String protocol) {if (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https")) {throw new IllegalArgumentException(String.format("Protocol: %s is not allowed. Allowed protocols are: http and https.",protocol));}} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(@Value("${app.server.protocol}") String protocol) {checkThatProtocolIsValid(protocol);this.protocol = protocol.toLowercase();}private void checkThatProtocolIsValid(String protocol) {if (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https")) {throw new IllegalArgumentException(String.format("Protocol: %s is not allowed. Allowed protocols are: http and https.",protocol));}} }

    這是一個(gè)維護(hù)問(wèn)題,因?yàn)锳和B類(lèi)包含復(fù)制粘貼代碼。 通過(guò)將驗(yàn)證邏輯移至實(shí)用程序類(lèi)并在創(chuàng)建新的A和B對(duì)象時(shí)使用它,可以稍微改善這種情況。

    完成此操作后,我們的源代碼如下所示:

    public final class ProtocolValidator {private ProtocolValidator() {}public static void checkThatProtocolIsValid(String protocol) {if (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https")) {throw new IllegalArgumentException(String.format("Protocol: %s is not allowed. Allowed protocols are: http and https.",protocol));}} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(@Value("${app.server.protocol}") String protocol) {ProtocolValidator.checkThatProtocolIsValid(protocol);this.protocol = protocol.toLowercase();} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(@Value("${app.server.protocol}") String protocol) {ProtocolValidator.checkThatProtocolIsValid(protocol);this.protocol = protocol.toLowercase();} }

    問(wèn)題在于,我們?nèi)匀槐仨氂涀∫{(diào)用此實(shí)用程序方法。 我們當(dāng)然可以通過(guò)使用代碼審閱來(lái)強(qiáng)制執(zhí)行此操作,但是再次重申,審閱者必須記住要檢查的另一件事。

    4.我們不能編寫(xiě)好的文檔

    我們無(wú)法編寫(xiě)描述應(yīng)用程序配置的好的文檔,因?yàn)槲覀儽仨殞⒋宋臋n添加到實(shí)際的屬性文件中,使用Wiki或編寫(xiě)* gasp * Word文檔。

    這些選項(xiàng)中的每個(gè)選項(xiàng)都會(huì)引起問(wèn)題,因?yàn)槲覀儾荒茉诰帉?xiě)需要從屬性文件中找到屬性值的代碼時(shí)同時(shí)使用它們。 如果需要閱讀文檔,則必須打開(kāi)“外部文檔”,這會(huì)導(dǎo)致上下文切換非常昂貴 。

    讓我們繼續(xù)前進(jìn),找出如何解決這些問(wèn)題。

    將屬性值注入配置Bean

    通過(guò)將屬性值注入配置Bean中,我們可以解決前面提到的問(wèn)題。 首先,為示例應(yīng)用程序創(chuàng)建一個(gè)簡(jiǎn)單的屬性文件。

    創(chuàng)建屬性文件

    我們要做的第一件事是創(chuàng)建一個(gè)屬性文件。 我們的示例應(yīng)用程序的屬性文件稱(chēng)為application.properties ,其外觀如下:

    app.name=Configuration Properties example app.production.mode.enabled=falseapp.server.port=8080 app.server.protocol=http app.server.host=localhost

    讓我們繼續(xù)并配置示例應(yīng)用程序的應(yīng)用程序上下文。

    配置應(yīng)用程序上下文

    我們的示例應(yīng)用程序的應(yīng)用程序上下文配置類(lèi)有兩個(gè)目標(biāo):

  • 啟用S??pring MVC并導(dǎo)入其默認(rèn)配置。
  • 確保已讀取從application.properties文件中找到的屬性值,并且可以將其注入到Spring Bean中。
  • 通過(guò)執(zhí)行以下步驟,我們可以實(shí)現(xiàn)第二個(gè)目標(biāo):

  • 配置Spring容器以?huà)呙杷邪琤ean類(lèi)的軟件包。
  • 確保從application.properties文件中找到的屬性值已讀取并添加到Spring Environment中 。
  • 確保從@Value批注中找到的$ {…}占位符替換為從當(dāng)前Spring Environment及其PropertySources中找到的屬性值。
  • WebAppContext類(lèi)的源代碼如下所示:

    import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc;@Configuration @ComponentScan({"net.petrikainulainen.spring.trenches.config","net.petrikainulainen.spring.trenches.web" }) @EnableWebMvc @PropertySource("classpath:application.properties") public class WebAppContext {/*** Ensures that placeholders are replaced with property values*/@BeanPropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {return new PropertySourcesPlaceholderConfigurer();} }

    補(bǔ)充閱讀:

    • @ComponentScan批注的Javadoc
    • @PropertySource批注的Javadoc
    • Spring框架參考手冊(cè)的5.13.4 @PropertySource部分
    • PropertySourcesPlaceholderConfigurer類(lèi)的Javadoc

    下一步是創(chuàng)建配置Bean類(lèi),并將從屬性文件中找到的屬性值注入到它們中。 讓我們找出如何做到這一點(diǎn)。

    創(chuàng)建配置Bean類(lèi)

    讓我們創(chuàng)建以下描述的兩個(gè)配置bean類(lèi):

    • WebProperties類(lèi)包含用于配置使用的協(xié)議,服務(wù)器的主機(jī)以及服務(wù)器偵聽(tīng)的端口的屬性值。
    • ApplicationProperties類(lèi)包含用于配置應(yīng)用程序名稱(chēng)并標(biāo)識(shí)是否啟用生產(chǎn)模式的屬性值。 它還具有對(duì)WebProperties對(duì)象的引用。

    首先 ,我們必須創(chuàng)建WebProperties類(lèi)。 我們可以按照以下步驟進(jìn)行操作:

  • 創(chuàng)建WebProperties類(lèi),并使用@Component注釋對(duì)其進(jìn)行注釋。
  • 將最終協(xié)議 , serverHost和serverPort字段添加到創(chuàng)建的類(lèi)中。
  • 通過(guò)使用構(gòu)造函數(shù)注入將屬性值注入這些字段,并確保協(xié)議字段的值必須為“ http”或“ https”(忽略大小寫(xiě))。
  • 添加用于獲取實(shí)際屬性值的吸氣劑。
  • WebProperties類(lèi)的源代碼如下所示:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;@Component public final class WebProperties {private final String protocol;private final String serverHost;private final int serverPort;@Autowiredpublic WebProperties(@Value("${app.server.protocol}") String protocol,@Value("${app.server.host}") String serverHost,@Value("${app.server.port}") int serverPort) {checkThatProtocolIsValid(protocol);this.protocol = protocol.toLowercase();this.serverHost = serverHost;this.serverPort = serverPort;}private void checkThatProtocolIsValid(String protocol) {if (!protocol.equalsIgnoreCase("http") && !protocol.equalsIgnoreCase("https")) {throw new IllegalArgumentException(String.format("Protocol: %s is not allowed. Allowed protocols are: http and https.",protocol));}}public String getProtocol() {return protocol;}public String getServerHost() {return serverHost;}public int getServerPort() {return serverPort;} }

    其次 ,我們必須實(shí)現(xiàn)ApplicationProperties類(lèi)。 我們可以按照以下步驟進(jìn)行操作:

  • 創(chuàng)建ApplicationProperties類(lèi),并使用@Component注釋對(duì)其進(jìn)行注釋。
  • 將最終名稱(chēng) , productionModeEnabled和webProperties字段添加到創(chuàng)建的類(lèi)。
  • 通過(guò)使用構(gòu)造函數(shù)注入,將屬性值和WebProperties Bean注入到ApplicationProperties Bean中。
  • 添加用于獲取字段值的吸氣劑。
  • ApplicationProperties類(lèi)的源代碼如下所示:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;@Component public final class ApplicationProperties {private final String name;private final boolean productionModeEnabled;private final WebProperties webProperties;@Autowiredpublic ApplicationProperties(@Value("${app.name}") String name,@Value("${app.production.mode.enabled:false}") boolean productionModeEnabled,WebProperties webProperties) {this.name = name;this.productionModeEnabled = productionModeEnabled;this.webProperties = webProperties;}public String getName() {return name;}public boolean isProductionModeEnabled() {return productionModeEnabled;}public WebProperties getWebProperties() {return webProperties;} }

    讓我們繼續(xù)研究該解決方案的好處。

    這對(duì)我們有什么幫助?

    現(xiàn)在,我們創(chuàng)建了包含從application.properties文件中找到的屬性值的Bean類(lèi)。 該解決方案似乎是一項(xiàng)過(guò)度的工程設(shè)計(jì),但與傳統(tǒng)的簡(jiǎn)單方法相比,它具有以下優(yōu)點(diǎn):

    1.我們只能注入一個(gè)Bean而不是多個(gè)屬性值

    如果我們將屬性值注入配置Bean,然后通過(guò)使用構(gòu)造函數(shù)注入將該配置Bean注入U(xiǎn)rlBuilder類(lèi),則其源代碼如下所示:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class UrlBuilder {private final WebProperties properties;@Autowiredpublic UrlBuilder(WebProperties properties) {this.properties = properties;} }

    如我們所見(jiàn),這使我們的代碼更整潔( 尤其是在使用構(gòu)造函數(shù)注入的情況下 )。

    2.我們只需指定一次屬性名稱(chēng)

    如果將屬性值注入到配置Bean中,則只能在一個(gè)地方指定屬性名稱(chēng)。 這意味著

    • 我們的代碼遵循關(guān)注點(diǎn)分離原則。 可從配置Bean中找到屬性名稱(chēng),而其他需要此信息的Bean不知道其來(lái)源。 他們只是使用它。
    • 我們的代碼遵循“ 不要重復(fù)自己”的原則。 因?yàn)閷傩悦Q(chēng)僅在一個(gè)位置(在配置Bean中)指定,所以我們的代碼更易于維護(hù)。

    另外,(IMO)我們的代碼看起來(lái)也更加簡(jiǎn)潔:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(WebProperties properties) {this.protocol = properties.getProtocol();} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(WebProperties properties) {this.protocol = properties.getProtocol();} }

    3.我們只需要編寫(xiě)一次驗(yàn)證邏輯

    如果將屬性值注入到配置Bean中,則可以將驗(yàn)證邏輯添加到配置Bean中,而其他Bean不必知道它。 這種方法具有三個(gè)好處:

    • 我們的代碼遵循關(guān)注點(diǎn)分離原則,因?yàn)榭梢詮呐渲胋ean(它所屬的地方)中找到驗(yàn)證邏輯。 其他的豆子不必知道。
    • 我們的代碼遵循“不要重復(fù)自己”的原則,因?yàn)轵?yàn)證邏輯是從一個(gè)地方找到的。
    • 創(chuàng)建新的bean對(duì)象時(shí),我們不必記住要調(diào)用驗(yàn)證邏輯,因?yàn)樵趧?chuàng)建配置bean時(shí)我們可以執(zhí)行驗(yàn)證規(guī)則。

    同樣,我們的源代碼看起來(lái)也更加干凈:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class A {private final String protocol;@Autowiredpublic A(WebProperties properties) {this.protocol = properties.getProtocol();} }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class B {private final String protocol;@Autowiredpublic B(WebProperties properties) {this.protocol = properties.getProtocol();} }

    4.我們可以從IDE中訪(fǎng)問(wèn)文檔

    我們可以通過(guò)向配置bean中添加Javadoc注釋來(lái)記錄應(yīng)用程序的配置。 完成此操作后,當(dāng)我們編寫(xiě)需要這些屬性值的代碼時(shí),可以從IDE中訪(fǎng)問(wèn)此文檔。 我們不需要打開(kāi)其他文件或閱讀維基頁(yè)面。 我們可以簡(jiǎn)單地繼續(xù)編寫(xiě)代碼并避免上下文切換的開(kāi)銷(xiāo) 。

    讓我們繼續(xù)并總結(jié)從這篇博客文章中學(xué)到的知識(shí)。

    摘要

    這篇博客文章告訴我們將屬性值注入配置Bean:

    • 幫助我們遵循關(guān)注點(diǎn)分離原則。 有關(guān)配置屬性和屬性值驗(yàn)證的內(nèi)容封裝在我們的配置Bean中。 這意味著使用這些配置bean的bean不知道屬性值來(lái)自何處或如何驗(yàn)證它們。
    • 幫助我們遵循“不要重復(fù)自己”的原則,因?yàn)?)我們只需指定一次屬性名稱(chēng),然后2)可以將驗(yàn)證邏輯添加到配置bean。
    • 使我們的文檔更易于訪(fǎng)問(wèn)。
    • 使我們的代碼更易于編寫(xiě),閱讀和維護(hù)。

    但是,這無(wú)助于我們弄清應(yīng)用程序的運(yùn)行時(shí)配置。 如果我們需要此信息,則必須讀取從服務(wù)器中找到的屬性文件。 這很麻煩。

    我們將在我的下一篇博客文章中解決此問(wèn)題。

    • PS:您可以從Github獲得此博客文章的示例應(yīng)用程序 。

    翻譯自: https://www.javacodegeeks.com/2015/04/spring-from-the-trenches-injecting-property-values-into-configuration-beans.html

    bean注入屬性

    總結(jié)

    以上是生活随笔為你收集整理的bean注入属性_摆脱困境:将属性值注入配置Bean的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。