ホームページ  >  記事  >  Java  >  SpringBoot の外部化を構成する方法

SpringBoot の外部化を構成する方法

WBOY
WBOY転載
2023-05-15 09:43:051163ブラウズ

SpringBoot の外部化された構成 (2.4.0 以降に基づく)

Spring Boot を使用すると、構成を外部化できるため、異なる環境で同じアプリケーション コードを使用できます。 Java プロパティ ファイル、YAML ファイル、環境変数、コマンド ライン パラメータなど、さまざまな外部構成ソースを使用できます。

プロパティ値は、@Value アノテーションを使用して Bean に直接挿入したり、Spring の環境を介してアクセスしたり、@ConfigurationProperties を介してオブジェクトにバインドしたりできます。同時に、Spring Boot は、ユーザーが適切なシナリオで特定のプロパティ値をオーバーライドできるようにする非常に特別な PropertyOrder も提供します。この順序は、値の合理的なオーバーライドを可能にするように設計されています。

優先度は次の順序で低から高になります。後者のプロパティ値は前者をオーバーライドします。すべての構成は補完的な構成を形成します:

Default プロパティ (SpringApplication.setDefaultProperties を使用して指定)

@Configurationクラスの @PropertySource アノテーションによって導入された構成プロパティ

このようなプロパティ ソースは、次の時点まで更新されないことに注意してください。 ApplicationContext が環境に追加されます。これでは、フラッシュが開始される前に読み取られた logging.* spring.main.* などの一部のプロパティを構成するには遅すぎます。

構成データ (application.properties ファイルなど)

random.* 形式のプロパティの場合、最初に RandomValuePropertySource から取得されます。 (優先順位を参照)

OS 環境変数((オペレーティング システム環境変数)

Java システム プロパティ(Java システム プロパティSystem.getProperties())

JNDI プロパティ

ServletContext の初期化パラメータ

ServletConfig の初期化パラメータ

SPRING_APPLICATION_JSON プロパティ

コマンド ライン パラメータ

properties プロパティテスト モジュールの下

テスト モジュールの下の @TestPropertySource アノテーションによって導入された構成ファイル

devtools が有効な場合の $HOME/.config/spring-boot パスの下の構成

構成データ ファイルは次のようにロードされます。 考慮すべきシーケンス:

  • jar にパッケージ化されたアプリケーション プロパティ (application.properties および YAML)

  • jar にパッケージ化された特定の構成ファイル アプリケーション プロパティ (application-{profile}.properties および YAML)

  • パッケージ化された jar の外にあるアプリケーション プロパティ (application.properties および YAML)

  • パッケージ化された jar の外部にある特定のプロファイルのアプリケーション プロパティ (application-{profile}.properties および YAML)

SpringBoot 構成ファイル

Spring の一般的な構成ファイルのタイプ

  • XML リソース

  • プロパティ リソース

  • YAML リソース

プロファイルの概要

プロファイルは基本的に、構成情報を整理するために使用されるディメンションを表し、さまざまなシナリオで異なる意味を表すことができます。たとえば、プロファイルがステータスを表す場合、次のように使用できます。オープン、ハーフオープン、クローズ、およびその他の値をそれぞれ完全に開いた状態、半分開いた状態、閉じた状態を表す別の例として、システムは一連のテンプレートを設定する必要があり、各テンプレートは一連の構成アイテムを保存します。

構成の命名規則:

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

構成ファイルのロード シーケンス

Spring Boot が開始すると、JAR パッケージ内の指定された場所に構成ファイル (プロパティ) が自動的にロードされます。 JAR パッケージが配置されているディレクトリ内の場所 (ファイル、YAML ファイル)。リストは優先度によって並べ替えられます (下位の項目の値は、前の項目の値をオーバーライドします)

classpath ( –classpath )

classpath root path

/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

プロファイル設定カバレッジの変更 (2.4.0 以降)

2.4.0以前のバージョンのデフォルトの読み込み順序は次のとおりでした:

  • jar にパッケージ化されたアプリケーション プロパティ (application.properties および YAML) 。

  • アプリケーション プロパティ (application.properties および YAML) を jar の外にパッケージ化する

  • プロファイル固有のアプリケーションを jar にパッケージ化する アプリケーション プロパティ (application.properties および YAML) {profile}.properties および YAML)

  • パッケージ化された jar の外のプロファイル固有のアプリケーション プロパティ (application-{profile}.properties および YAML)

注: 以前のバージョンでは、JAR パッケージ外の

application.properties 構成ファイルは、JAR パッケージ内の「プロファイル」ベースの アプリケーションを上書きしませんでした。 構成ファイル。

2.4.0以降のバージョンでは、デフォルトの検索順序は次のとおりです。JAR パッケージ外部のアプリケーション パラメータが、JAR パッケージ内部の特定のアクティベーション構成パラメータよりも優先されるようにします。

    jar にパッケージ化されたアプリケーション プロパティ (application.properties および YAML)。
  • jar にパッケージ化されたプロファイル固有のアプリケーション プロパティ (application-{profile}.properties および YAML)
  • jar の外部にパッケージ化されたアプリケーション プロパティapplication.properties と YAML
  • 打包 jar 之外的特定于配置文件的应用程序属性(application-{profile}.properties 和 YAML)

注意:同一位置下,Properties 文件优先级高于 YAML 文件 , 如果Spring Boot在优先级更高的位置找到了配置,那么它就会无视优先级低的配置。

文档排序(2.4.0以后)

从 Spring Boot 2.4 开始,加载 Properties 和 YAML 文件时候会遵循, 在文档中声明排序靠前的属性将被靠后的属性覆盖 。

激活指定配置文件

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

spring:
  profiles:
    active: dev #激活开发环境配置

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

注意:在application.yml或者properties文件存在的情况下,不管激活的是prod还是dev,还是会读取默认的配置文件,只不过指定的配置文件会覆盖默认配置文件中的属性

导入额外的配置文件(2.4.0以后)

可以使用spring.config.import属性从其他地方导入更多的配置数据,比如spring.config.import=my.yaml 。它会将 my.yaml 文件作为临时文件放在当前配置文件之后处理,因此其属性具有更高的优先级

激活外部配置文件

在运行Jar包的命令中加入这个参数就可以指定Jar包以外的配置文件的位置了,也可以在application的配置文件中配置该属性

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

这个参数就是指定外部application.yml配置文件位置的参数,它支持classpathfile路径

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

如果您不喜欢application.properties作为配置文件名,您可以通过指定spring.config.name环境属性来切换到另一个文件名

optional可选的配置文件

对于spring.config.locationspring.config.additional-locationspring.config.import等属性的路径,添加optional:前缀,则当对应文件不存在时应用仍可以正常启动

比如spring.config.location=optional:file:/my.yaml,当应用启动加载文件 my.yaml 不存在时,不会抛出异常

嵌入系统配置信息

例如,如果想要获取当前应用程序的名称并作为一个配置项进行管理,那么很简单,我们直接通过 ${spring.application.name} 占位符:

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

假设我们使用 Maven 来构建应用程序,那么可以按如下所示的配置项来动态获取与系统构建过程相关的信息:

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

配置参数提示

additional-spring-configuration-metadata.jsonspring-configuration-metadata.json在springboot-starter官方项目或第三方starter项目中随处可见,那它起的作用是什么?

  • 配置additional-spring-configuration-metadata.json文件后,在开发人员的IDE工具使用个人编写的配置读取很有效的在application.propertiesapplication.yml文件下完成提示

配置处理器

在Maven中,该依赖关系应被声明为可选的,如以下例子所示。

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

创建additional-spring-configuration-metadata.json

resources/META-INF目录下创建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 数组中包含的JSON对象可以包含下表中描述的属性。

#名前タイプ目的名前文字列属性の完全な名前。名前は小文字でピリオドで区切られます (server.address など)。この属性は必須です。 typeString プロパティのデータ型 (java.lang.String など) の完全な署名ですが、完全な署名もあります。ジェネリック型 (例: java.util.Map)。このプロパティを使用して、ユーザーに入力できる値の種類を指示できます。一貫性を保つために、プリミティブの型はラッパー型を使用して指定されます (たとえば、boolean は java.lang.Boolean になります)。タイプが不明な場合は省略できます。 descriptionStringユーザーに表示できるプロパティの短い説明。記載がない場合は省略可能です。説明の最後の行はピリオド (.) で終わる必要があります。 sourceTypeStringこのプロパティを提供したソースのクラス名。たとえば、プロパティが @ConfigurationProperties アノテーションが付けられたクラスからのものである場合、プロパティにはクラスの完全修飾名が含まれます。ソースタイプが不明な場合は省略できます。 defaultValueObjectデフォルト値。このプロパティが指定されていない場合は、この値が使用されます。プロパティの型が配列の場合は、値の配列にすることができます。デフォルト値が不明な場合は省略できます。 deprecationDeprecation属性が非推奨かどうかを指定します。このフィールドが廃止されていない場合、またはこの情報が不明な場合は省略できます。次の表に、非推奨属性の詳細を示します。
ヒント プロパティ
ヒント配列に含まれる JSON オブジェクトには、次の表のプロパティを含めることができます。

#名前名前values各ヒント要素のvalues属性に含まれるJSONオブジェクトには、次の表で説明するプロパティを含めることができます。
タイプ 目的
文字列 このヒントが示すプロパティの完全な名前。名前は小文字のピリオドで区切られた形式です (spring.mvc.servlet.path など)。この属性は必須です。
ValueHint[] ValueHint オブジェクトによって定義される有効な値のリスト (次の表で説明)。各エントリには定義された値があり、説明を含めることができます。

#名前タイプ目的値オブジェクトヒントが指す要素の有効な値。プロパティの型が配列の場合は、配列値にすることもできます。この属性は必須です。 descriptionStringユーザーに表示できる値の短い説明。記載がない場合は省略可能です。説明の最後の行はピリオド (.) で終わる必要があります。

SpringBoot命令行参数

参考:https://www.yisu.com/article/191629.htm

启动Spring Boot项目时传递参数,有三种参数形式:

  • 选项参数,基本格式为--optName[=optValue]--为连续两个减号)

--foo
--foo=bar
--foo="bar then baz"
--foo=bar,baz,biz
  • 非选项参数

java -jar xxx.jar abc def

  • 系统参数

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

相当于 SpringBoot 基于 Java 命令行参数中的非选项参数自定义了选项参数的规则,具体可以看解析器SimpleCommandLineArgsParser,它里面调用其parse方法对参数进行解析

class SimpleCommandLineArgsParser {
    public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        for (String arg : args) {
            // --开头的选参数解析
            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(&#39;=&#39;));
                    optionValue = optionText.substring(optionText.indexOf(&#39;=&#39;)+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;
    }
}

参数值的获取

如果您需要访问传递给应用程序的参数SpringApplication.run(…),您可以注入一个ApplicationArguments。该ApplicationArguments接口提供对原始String[]参数以及选项参数和非选项参数的访问,如以下示例所示:

@Component
public class MyBean {
    @Autowired
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    }
}
  • 另外,选项参数,也可以直接通过@Value在类中获取

  • 系统参数可以通过java.lang.System提供的方法获取

参数值的区别

关于参数值区别,重点看选项参数和系统参数。通过上面的示例我们已经发现使用选项参数时,参数在命令中是位于xxx.jar之后传递的,而系统参数是紧随java -jar之后。

如果不按照该顺序进行执行,比如使用如下方式使用选项参数:

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.

如果将系统参数放在jar包后面,问题会更严重,会出现可以正常启动,但参数无法生效。这个错误是最坑的,所以一定谨记:通过-D传递系统参数时,务必放置在待执行的jar包之前。

扩展“外部化配置”属性源

SpringBoot の外部化を構成する方法

SpringBoot の外部化を構成する方法

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

处理@PropertySource注解从ConfigurationClassParser#processPropertySource方法进

Spring中@PropertySource默认不支持YAML格式的解析,但是SpringBoot的配置文件却可以解析YAML,这说明SpringBoot中已经实现了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的默认实现是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,所以我们可以通过实现PropertySourceFactory接口,然后用@PropertySource的factory属性来实现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没有被执行的原因

官方文档中有说到:有些事件实际上是在ApplicationContext被创建之前触发的,所以我们不能将这些事件的监听器注册为@Bean。

因为这个时候应用上下文还没有被创建,也就是说监听器也还没有被初始化,这个先后顺序不对,会导致这些事件的监听器不会被触发

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

如果您希望这些侦听器自动注册的话,可以通过新建一个META-INF/spring.factories文件,添加类似以下内容,SpringBoot会自动帮你注册。

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

应用程序运行时,应用程序事件按以下顺序发送:

  • 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.

  • AvailabilityChangeEvent は ReadinessState.ACCEPTING_TRAFFIC の直後に送信され、アプリケーションがリクエストを処理する準備ができていることを示します。

  • ApplicationFailedEvent は、起動時の例外。

上記のリストには、SpringApplication に関連付けられた SpringApplicationEvent のみが含まれています。これらに加えて、次のイベントも ApplicationPreparedEvent の後、ApplicationStartedEvent の前に発行されます。

  • WebServerInitializedEvent は、Web サーバーの準備ができた後に送信されます。 ServletWebServerInitializedEvent と ReactiveWebServerInitializedEvent は、それぞれサーブレットとリアクティブのバリアントです。

  • ContextRefreshedEvent は、ApplicationContext が更新されるときに送信されます。

以上がSpringBoot の外部化を構成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。