溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot外部化如何配置

發(fā)布時間:2023-02-25 10:15:36 來源:億速云 閱讀:135 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹了SpringBoot外部化如何配置的相關知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇SpringBoot外部化如何配置文章都會有所收獲,下面我們一起來看看吧。

SpringBoot外部化配置(基于2.4.0以后)

Spring Boot可以讓你將配置外部化,這樣你就可以在不同的環(huán)境中使用相同的應用程序代碼。 你可以使用各種外部配置源,包括Java properties 文件、YAML文件、環(huán)境變量和命令行參數(shù)。

屬性值可以通過使用 @Value 注解直接注入你的Bean,也可以通過Spring 的 Environment 訪問,或者通過 @ConfigurationProperties 綁定到對象。同時 Spring Boot 也提供了一種非常特殊的 PropertyOrder,來允許用戶可以在適當?shù)膱鼍跋赂采w某些屬性值,該順序旨在允許合理地覆蓋值。

按以下順序優(yōu)先級從低到高, 后者的屬性值覆蓋前者 ,所有的配置會形成互補配置:

默認屬性(使用 SpringApplication.setDefaultProperties 指定)

@Configuration類上的@PropertySource注解引入的配置屬性

請注意,這樣的屬性源直到ApplicationContext被刷新時才會被添加到環(huán)境中。這對于配置某些屬性來說已經(jīng)太晚了,比如logging.* spring.main.* ,它們在刷新開始前就已經(jīng)被讀取了。

配置數(shù)據(jù)(例如application.properties文件)

對于random.*形式的屬性,優(yōu)先從RandomValuePropertySource獲?。ㄖ竷?yōu)先于后者)

OS environment variables((操作系統(tǒng)環(huán)境變量)

Java System properties(Java 系統(tǒng)屬性System.getProperties()

JNDI 屬性

ServletContext 的 初始化參數(shù)

ServletConfig 的 初始化參數(shù)

SPRING_APPLICATION_JSON 屬性

命令行參數(shù)

test 模塊下的 properties 屬性

test 模塊下 @TestPropertySource 注解引入的配置文件

啟用 devtools 時 $HOME/.config/spring-boot 路徑下的配置

配置數(shù)據(jù)文件按以下加載順序考慮:

  • 打包在 jar 中的應用程序?qū)傩裕╝pplication.properties 和 YAML)

  • 打包在 jar 中的特定配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

  • 打包 jar 之外的應用程序?qū)傩裕╝pplication.properties 和 YAML)

  • 打包 jar 之外的特定配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

SpringBoot配置文件

Spring中常見的配置文件類型

  • XML資源

  • Properties資源

  • YAML資源

Profile概述

Profile 本質(zhì)上代表一種用于組織配置信息的維度,在不同場景下可以代表不同的含義。例如,如果 Profile 代表的是一種狀態(tài),我們可以使用 open、halfopen、close 等值來分別代表全開、半開和關閉等。再比如系統(tǒng)需要設置一系列的模板,每個模板中保存著一系列配置項。

配置命名規(guī)則:

/{application}.yml
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

配置文件加載順序

Spring Boot 啟動時,會自動加載 JAR 包內(nèi)部及 JAR 包所在目錄指定位置的配置文件(Properties 文件、YAML 文件)。列表按優(yōu)先級排序(較低項目的值覆蓋較早項目的值)

classpath( –classpath )

classpath 根路徑

classpath 下的 /config 包

當前目錄( –file )

當前目錄下

當前目錄下的 config/ 子目錄

當前目錄下的 config/ 子目錄的直接子目錄

. project-sample
├── config
│   ├── application.yml (4)
│   └── src/main/resources
|   │   ├── application.yml (1)
|   │   └── config
|   |   │   ├── application.yml (2)
├── application.yml (3)

啟動時加載配置文件順序:1 > 2 > 3 > 4

Profile 配置覆蓋變更(2.4.0以后)

2.4.0以前版本,默認情況的加載順序如下:

  • 打包在 jar 中的應用程序?qū)傩裕╝pplication.properties 和 YAML)。

  • 打包 jar 之外的應用程序?qū)傩裕╝pplication.properties 和 YAML)

  • 打包在 jar 中的特定于配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

  • 打包 jar 之外的特定于配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

注意:在之前的版本中,JAR 包外部的application.properties配置文件不會覆蓋 JAR 包里面的基于 "profile" 的application-{profile}.properties 配置文件。

2.4.0以后版本,默認情況的搜索順序如下:保證了 JAR 包外部的應用程序參數(shù)應優(yōu)先于 JAR 包內(nèi)部的特定激活的配置參數(shù)

  • 打包在 jar 中的應用程序?qū)傩裕╝pplication.properties 和 YAML)。

  • 打包在 jar 中的特定于配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

  • 打包 jar 之外的應用程序?qū)傩裕╝pplication.properties 和 YAML)

  • 打包 jar 之外的特定于配置文件的應用程序?qū)傩裕╝pplication-{profile}.properties 和 YAML)

注意:同一位置下,Properties 文件優(yōu)先級高于 YAML 文件 , 如果Spring Boot在優(yōu)先級更高的位置找到了配置,那么它就會無視優(yōu)先級低的配置。

文檔排序(2.4.0以后)

從 Spring Boot 2.4 開始,加載 Properties 和 YAML 文件時候會遵循, 在文檔中聲明排序靠前的屬性將被靠后的屬性覆蓋 。

激活指定配置文件

命令行激活: --spring.profiles.active=prod 

spring:
  profiles:
    active: dev #激活開發(fā)環(huán)境配置

配置文件激活如上,只需要在application.yml或者properties文件中配置即可

注意:在application.yml或者properties文件存在的情況下,不管激活的是prod還是dev,還是會讀取默認的配置文件,只不過指定的配置文件會覆蓋默認配置文件中的屬性

導入額外的配置文件(2.4.0以后)

可以使用spring.config.import屬性從其他地方導入更多的配置數(shù)據(jù),比如spring.config.import=my.yaml 。它會將 my.yaml 文件作為臨時文件放在當前配置文件之后處理,因此其屬性具有更高的優(yōu)先級

激活外部配置文件

在運行Jar包的命令中加入這個參數(shù)就可以指定Jar包以外的配置文件的位置了,也可以在application的配置文件中配置該屬性

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

這個參數(shù)就是指定外部application.yml配置文件位置的參數(shù),它支持classpathfile路徑

java -jar myproject.jar --spring.config.name=myproject

如果您不喜歡application.properties作為配置文件名,您可以通過指定spring.config.name環(huán)境屬性來切換到另一個文件名

optional可選的配置文件

對于spring.config.location、spring.config.additional-locationspring.config.import等屬性的路徑,添加optional:前綴,則當對應文件不存在時應用仍可以正常啟動

比如spring.config.location=optional:file:/my.yaml,當應用啟動加載文件 my.yaml 不存在時,不會拋出異常

嵌入系統(tǒng)配置信息

例如,如果想要獲取當前應用程序的名稱并作為一個配置項進行管理,那么很簡單,我們直接通過 ${spring.application.name} 占位符:

myapplication.name : ${spring.application.name}

假設我們使用 Maven 來構建應用程序,那么可以按如下所示的配置項來動態(tài)獲取與系統(tǒng)構建過程相關的信息:

info: 
  app:
    encoding: @project.build.sourceEncoding@
    java:
      source: @java.version@
      target: @java.version@
# 等同于下述效果
info:
  app:
    encoding: UTF-8
    java:
        source: 1.8.0_31
        target: 1.8.0_31

配置參數(shù)提示

additional-spring-configuration-metadata.json、spring-configuration-metadata.json在springboot-starter官方項目或第三方starter項目中隨處可見,那它起的作用是什么?

  • 配置additional-spring-configuration-metadata.json文件后,在開發(fā)人員的IDE工具使用個人編寫的配置讀取很有效的在application.propertiesapplication.yml文件下完成提示

配置處理器

在Maven中,該依賴關系應被聲明為可選的,如以下例子所示。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

創(chuàng)建additional-spring-configuration-metadata.json

resources/META-INF目錄下創(chuàng)建additional-spring-configuration-metadata.json,分類為 “groups” 或 “properties”,附加值提示分類為 "hints",如以下例子所示:

{
    "groups": [
        {
            "name": "server",
            "type": "org.springframework.boot.autoconfigure.web.ServerProperties",
            "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
        },
        {
            "name": "spring.jpa.hibernate",
            "type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate",
            "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties",
            "sourceMethod": "getHibernate()"
        }
    ...
    ],
    "properties": [
        {
            "name": "server.port",
            "type": "java.lang.Integer",
            "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
        },
        {
            "name": "server.address",
            "type": "java.net.InetAddress",
            "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
        },
        {
            "name": "spring.jpa.hibernate.ddl-auto",
            "type": "java.lang.String",
            "description": "DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property.",
            "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate"
        }
    ...
    ],
    "hints": [
        {
            "name": "spring.jpa.hibernate.ddl-auto",
            "values": [
                {
                    "value": "none",
                    "description": "Disable DDL handling."
                },
                {
                    "value": "validate",
                    "description": "Validate the schema, make no changes to the database."
                },
                {
                    "value": "update",
                    "description": "Update the schema if necessary."
                },
                {
                    "value": "create",
                    "description": "Create the schema and destroy previous data."
                },
                {
                    "value": "create-drop",
                    "description": "Create and then destroy the schema at the end of the session."
                }
            ]
        }
    ]
}
Property 屬性

properties 數(shù)組中包含的JSON對象可以包含下表中描述的屬性。

Name類型目的
nameString屬性的全名。 名稱采用小寫的句號分隔形式(例如,server.address)。 這個屬性是強制性的。
typeString該屬性的數(shù)據(jù)類型的完整簽名(例如,java.lang.String),但也有完整的通用類型(例如 java.util.Map<java.lang.String,com.example.MyEnum>)。 您可以使用此屬性來指導用戶可以輸入的值的類型。 為了保持一致性,基元的類型是通過使用其包裝類型來指定的(例如,boolean 變成 java.lang.Boolean)。 如果該類型不知道,可以省略。
descriptionString可以顯示給用戶的該property的簡短描述。 如果沒有描述,可以省略。 描述中的最后一行應以句號(.)結(jié)束。
sourceTypeString貢獻此屬性的來源的類名。 例如,如果該屬性來自于一個用 @ConfigurationProperties 注解的類,該屬性將包含該類的完全限定名稱。 如果源類型未知,可以省略。
defaultValueObject默認值,如果沒有指定該屬性,則使用該值。 如果該屬性的類型是一個數(shù)組,它可以是一個數(shù)組的值。 如果默認值是未知的,它可以被省略。
deprecationDeprecation指定該屬性是否被廢棄。 如果該字段沒有被廢棄,或者不知道該信息,可以省略。 下表提供了關于 deprecation 屬性的更多細節(jié)。
Hint 屬性

包含在 hints 數(shù)組中的JSON對象可以包含下表中的屬性。

Name類型目的
nameString此提示所指向的屬性的全名。 名稱采用小寫的句號分隔形式(如 spring.mvc.servlet.path)。 這個屬性是強制性的。
valuesValueHint[]由 ValueHint 對象定義的有效值的列表(在下表中描述)。 每個條目都定義了值,并且可以有一個description。

每個 hint 元素的 values 屬性中包含的JSON對象可以包含下表中描述的屬性。

Name類型目的
valueObject提示所指的元素的一個有效值。 如果該屬性的類型是一個數(shù)組,它也可以是一個數(shù)組的值。 這個屬性是強制性的。
descriptionString可以顯示給用戶的價值的簡短描述。 如果沒有描述,可以省略。 描述中的最后一行應以句號(.)結(jié)束。

SpringBoot命令行參數(shù)

參考:http://www.kemok4.com/article/191629.htm

啟動Spring Boot項目時傳遞參數(shù),有三種參數(shù)形式:

  • 選項參數(shù),基本格式為--optName[=optValue]--為連續(xù)兩個減號)

--foo
--foo=bar
--foo="bar then baz"
--foo=bar,baz,biz
  • 非選項參數(shù)

java -jar xxx.jar abc def

  • 系統(tǒng)參數(shù)

java -jar -Dserver.port=8081 xxx.jar

相當于 SpringBoot 基于 Java 命令行參數(shù)中的非選項參數(shù)自定義了選項參數(shù)的規(guī)則,具體可以看解析器SimpleCommandLineArgsParser,它里面調(diào)用其parse方法對參數(shù)進行解析

class SimpleCommandLineArgsParser {
    public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        for (String arg : args) {
            // --開頭的選參數(shù)解析
            if (arg.startsWith("--")) {
                // 獲得key=value或key值
                String optionText = arg.substring(2, arg.length());
                String optionName;
                String optionValue = null;
                // 如果是key=value格式則進行解析
                if (optionText.contains("=")) {
                    optionName = optionText.substring(0, optionText.indexOf('='));
                    optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
                } else {
                    // 如果是僅有key(--foo)則獲取其值
                    optionName = optionText;
                }
                // 如果optionName為空或者optionValue不為空但optionName為空則拋出異常
                if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                // 封裝入CommandLineArgs
                commandLineArgs.addOptionArg(optionName, optionValue);
            } else {
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
    }
}

參數(shù)值的獲取

如果您需要訪問傳遞給應用程序的參數(shù)SpringApplication.run(&hellip;),您可以注入一個ApplicationArguments。該ApplicationArguments接口提供對原始String[]參數(shù)以及選項參數(shù)和非選項參數(shù)的訪問,如以下示例所示:

@Component
public class MyBean {
    @Autowired
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List&lt;String&gt; files = args.getNonOptionArgs();
        // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    }
}
  • 另外,選項參數(shù),也可以直接通過@Value在類中獲取

  • 系統(tǒng)參數(shù)可以通過java.lang.System提供的方法獲取

參數(shù)值的區(qū)別

關于參數(shù)值區(qū)別,重點看選項參數(shù)和系統(tǒng)參數(shù)。通過上面的示例我們已經(jīng)發(fā)現(xiàn)使用選項參數(shù)時,參數(shù)在命令中是位于xxx.jar之后傳遞的,而系統(tǒng)參數(shù)是緊隨java -jar之后。

如果不按照該順序進行執(zhí)行,比如使用如下方式使用選項參數(shù):

java -jar --server.port=8081 xxx.jar

則會拋出如下異常:

Unrecognized option: --server.port=8081
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

如果將系統(tǒng)參數(shù)放在jar包后面,問題會更嚴重,會出現(xiàn)可以正常啟動,但參數(shù)無法生效。這個錯誤是最坑的,所以一定謹記:通過-D傳遞系統(tǒng)參數(shù)時,務必放置在待執(zhí)行的jar包之前。

擴展“外部化配置”屬性源

SpringBoot外部化如何配置

SpringBoot外部化如何配置

SpingBoot怎么支持YAML配置文件解析?

處理@PropertySource注解從ConfigurationClassParser#processPropertySource方法進

Spring中@PropertySource默認不支持YAML格式的解析,但是SpringBoot的配置文件卻可以解析YAML,這說明SpringBoot中已經(jīng)實現(xiàn)了YAML文件的解析,我們只需要復用即可,我們可以看該注解源碼

/**
 * Specify a custom {@link PropertySourceFactory}, if any.
 * <p>By default, a default factory for standard resource files will be used.
 * @since 4.3
 * @see org.springframework.core.io.support.DefaultPropertySourceFactory
 * @see org.springframework.core.io.support.ResourcePropertySource
 */
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;

PropertySourceFactory的默認實現(xiàn)是DefaultPropertySourceFactory

public class DefaultPropertySourceFactory implements PropertySourceFactory {
	@Override
	public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
		return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource));
	}
}

ResourcePropertySource默認不支持YAML,所以我們可以通過實現(xiàn)PropertySourceFactory接口,然后用@PropertySource的factory屬性來實現(xiàn)YAML的解析

public class YamlPropertySourceFactory implements PropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(resource.getResource());
        Properties yamlProperties = yamlPropertiesFactoryBean.getObject();
        return new PropertiesPropertySource(name, yamlProperties);
    }
}

關于ApplicationEnvironmentPreparedEvent沒有被執(zhí)行的原因

官方文檔中有說到:有些事件實際上是在ApplicationContext被創(chuàng)建之前觸發(fā)的,所以我們不能將這些事件的監(jiān)聽器注冊為@Bean。

因為這個時候應用上下文還沒有被創(chuàng)建,也就是說監(jiān)聽器也還沒有被初始化,這個先后順序不對,會導致這些事件的監(jiān)聽器不會被觸發(fā)

但可以使用SpringApplication.addListeners(...) 方法或SpringApplicationBuilder.listeners(...) 方法注冊它們。

如果您希望這些偵聽器自動注冊的話,可以通過新建一個META-INF/spring.factories文件,添加類似以下內(nèi)容,SpringBoot會自動幫你注冊。

org.springframework.context.ApplicationListener=com.example.project.MyListener
應用程序事件

應用程序運行時,應用程序事件按以下順序發(fā)送:

  • An ApplicationStartingEvent is sent at the start of a run but before any processing, except for the registration of listeners and initializers.

  • An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known but before the context is created.

  • An ApplicationContextInitializedEvent is sent when the ApplicationContext is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded.

  • An ApplicationPreparedEvent is sent just before the refresh is started but after bean definitions have been loaded.

  • An ApplicationStartedEvent is sent after the context has been refreshed but before any application and command-line runners have been called.

  • An AvailabilityChangeEvent is sent right after with LivenessState.CORRECT to indicate that the application is considered as live.

  • An ApplicationReadyEvent is sent after any application and command-line runners have been called.

  • An AvailabilityChangeEvent is sent right after with ReadinessState.ACCEPTING_TRAFFIC to indicate that the application is ready to service requests.

  • An ApplicationFailedEvent is sent if there is an exception on startup.

The above list only includes SpringApplicationEvents that are tied to a SpringApplication. In addition to these, the following events are also published after ApplicationPreparedEvent and before ApplicationStartedEvent:

  • A WebServerInitializedEvent is sent after the WebServer is ready. ServletWebServerInitializedEvent and ReactiveWebServerInitializedEvent are the servlet and reactive variants respectively.

  • A ContextRefreshedEvent is sent when an ApplicationContext is refreshed.

關于“SpringBoot外部化如何配置”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“SpringBoot外部化如何配置”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI