百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

精通Spring Boot 3 : Spring Boot 的内部机制 (3)

myzbx 2025-01-09 14:47 13 浏览

Spring Boot 的特点

现在,让我们通过使用我们的 My Retro App 项目来探索一些 Spring Boot 的功能。如果你查看主类,会发现 SpringApplication.run 方法。这个方法可以通过不同的方式进行实例化,以便利用其他功能;请参考列表 2-7。

package com.apress.myretro;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyretroApplication {
    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(MyretroApplication.class);
                  // Spring Application features ...
                  sa.run(args);
    }
}

列表 2-7 源代码:src/main/java/com/apress/myretro/MyretroApplication.java

列表 2-7 展示了与列表 2-2 之间的小修改。在这里,我们没有使用静态的 run(...args)方法调用。如果你查看 SpringApplication 类提供的选项(通过在 IDE 中输入实例变量 sa.并使用代码补全功能),你会看到一个与图 2-7 中所示(部分)相似的列表。


图 2-7 展示了 SpringApplication 实例变量的代码补全。接下来的部分将介绍一些您可以为 Spring Boot 应用程序添加的常见功能。

自定义广告横幅

当您启动应用程序时,会显示一个横幅。默认情况下是 Spring Boot 的 ASCII 艺术。请参见图 2-8。


在 SpringApplication 类中,您可以通过多种方式添加自定义横幅。您可以按照清单 2-8 中的示例以编程方式实现。

package com.apress.myretro;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
@SpringBootApplication
public class MyretroApplication {
    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(MyretroApplication.class);
        sa.setBanner(new Banner() {
                    @Override
                    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
                        out.println("\n\n\tThis is my custom Banner!\n\n".toUpperCase());
            }
        });
        sa.run(args);
    }
}

列表 2-8 源代码:src/main/java/com/apress/myretro/MyretroApplication.java

列表 2-8 展示了如何通过调用 setBanner(Banner)方法来实现自定义横幅。如果您运行这个程序,您将看到类似于图 2-9 的内容。


另一种创建自定义横幅的方法是使用 ASCII 艺术。有一些网站可以为您生成这些艺术作品。例如,您可以访问 https://www.patorjk.com,向下滚动页面,点击“文本转 ASCII 艺术生成器”链接,然后输入“我的复古”。图 2-10 展示了选择不同字体时文本的效果。


您可以浏览和尝试各种字体,选择您喜欢的字体。点击“选择并复制”按钮。接下来,您需要在 src/main/resources 目录下创建一个 banner.txt 文件,并粘贴 ASCII 艺术。图 2-11 显示了 banner.txt 文件及其 ASCII 艺术。

还要注意在图 2-11 中,我们在我的复古应用程序中添加了一个标题${spring-boot.version}。这是一个在运行时设置的全局属性,它将显示所使用的 Spring Boot 版本。如果您运行我的复古应用程序,您应该会看到与图 2-12 中所示的结果相同。



默认情况下,Spring Boot 会在资源文件夹中查找 banner.txt 文件,但您可以指定其他位置或文件扩展名。例如,您可以创建 src/main/resources/META-INF 文件夹并添加 banner.txt 文件。请参见图 2-13。


要使这项工作正常进行,您需要使用 spring.banner.location 属性。如果您想在 IDE 中使用它,您需要了解如何覆盖 Spring Boot 的配置属性。如果您使用的是 IntelliJ IDEA,请选择“编辑配置” ? “修改选项”,找到“覆盖配置属性”部分,并添加 spring.banner.location 和 classpath:/META-INF/banner.txt,如图 2-14 所示。


如果您使用 VS Code,您需要修改 launch.json 文件,并添加 env 键,值为 spring.banner.location 和 classpath:/META-INF/banner.txt。请参见图 2-15。



如果您希望通过命令行运行应用程序,请在 build.gradle 文件的末尾添加以下代码片段:

bootRun {
    systemProperties = System.properties
}

然后你可以执行以下命令,期待得到与图 2-12 中相同的结果:

./gradlew bootRun -Dspring.banner.location=classpath:/META-INF/banner.txt

正如你所看到的,有多种方式可以配置这些功能。如果你完全不需要横幅,可以使用如清单 2-9 所示的 setBanner(Mode)方法。

package com.apress.myretro;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
@SpringBootApplication
public class MyretroApplication {
    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(MyretroApplication.class);
        sa.setBannerMode(Banner.Mode.OFF);
        sa.run(args);
    }
}

列表 2-9 源代码:src/main/java/com/apress/myretro/MyretroApplication.java

Spring 应用程序构建器

Spring Boot 提供了一个流畅的构建器 API,允许您配置应用程序。该 API 引入了 ApplicationContext(来自 Spring 框架),使您的应用程序更加灵活可定制。列表 2-10 展示了 SpringApplicationBuilder 类,您可以在其中自定义应用程序的启动过程。

package com.apress.myretro;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
@SpringBootApplication
public class MyretroApplication {
    static Logger  log = LoggerFactory.getLogger(MyretroApplication.class);
    public static void main(String[] args) {
        new SpringApplicationBuilder()
                    .sources(MyretroApplication.class)
                    .logStartupInfo(false)
                    .bannerMode(Banner.Mode.OFF)
                    .lazyInitialization(true)
                    .web(WebApplicationType.NONE)
                    .profiles("cloud")
                    .listeners(event -> log.info("Event: {}",event.getClass().getCanonicalName()))
                    .run(args);
    }
}

列表 2-10 源代码:src/main/java/com/apress/myretro/MyretroApplication.java

让我们来分析一下列表 2-10 中展示的代码:

  • .sources(Class...): 这个方法是您添加应用程序所需的所有配置类和组件的地方。请记住,这些类需要标记为@Configuration,或者使用其他 Spring 相关的注解,如@Component、@Service、@Repository 等。
  • .logStartup(boolean): 此方法会将所有启动相关的日志信息输出到控制台。它接受一个布尔值,如果您将其设置为 false,您将看不到任何信息(或者只会看到您自己的日志,如果有的话)。
  • .bannerMode(模式):此方法接受一个模式参数,用于控制横幅的显示与否。可选值包括 Banner.Mode.OFF(禁用横幅打印)、Banner.Mode.CONSOLE(将横幅打印到 System.out)和 Banner.Mode.LOG(将横幅打印到日志文件)。
  • .lazyInitialization(boolean):此方法接受一个布尔值,默认值为 false。如果设置为 true,则在需要该 bean 之前不会进行创建。
  • .web(WebApplicationType): 此方法定义了 web 应用程序的类型。可选值包括 WebApplicationType.NONE(表示应用程序不应作为 web 应用程序运行,也不应启动嵌入式 web 服务器)、WebApplicationType.SERVLET(表示应用程序应作为基于 servlet 的 web 应用程序运行,并启动嵌入式 servlet web 服务器;如果您将 spring-boot-starter-web 作为依赖项/类路径,则此项为真),以及 WebApplicationType.REACTIVE(表示应用程序应作为反应式 web 应用程序运行,并启动嵌入式反应式 web 服务器,您需要将 spring-boot-starter-webflux 作为依赖项/类路径)。
  • .profiles(String...): 此方法列出可用的 Spring 配置文件。在运行应用程序时,您应该会看到输出“当前活动的配置文件为:‘cloud’”。(本章最后部分将详细讨论应用程序配置文件。)
  • .listeners(ApplicationListener...): 这个方法让您可以定义 Spring 事件。在我的复古应用程序中,我们监听所有 ApplicationListener 接口的实现,因此如果您运行该应用程序,您应该会看到如下输出:
Event: o.s.boot.context.event.ApplicationPreparedEvent
Event: o.s.context.event.ContextRefreshedEvent
Event: o.s.boot.context.event.ApplicationStartedEvent
Event: o.s.boot.availability.AvailabilityChangeEvent
Event: o.s.boot.context.event.ApplicationReadyEvent
Event: o.s.boot.availability.AvailabilityChangeEvent
Event: o.s.context.event.ContextClosedEvent

运行(String...): 这个方法允许您传递任何参数,正如您在本章前面看到的。如果您仍在使用 META-INF/banner.txt,并且横幅模式设置为 Banner.Mode.Console,您可以将以下内容添加到 args 中:

.run("--spring.banner.location=classpath:/META-INF/banner.txt");

应用程序的参数

在任何 Java 应用中,您都可以将有用的参数传递给主类,Spring Boot 会通过提供 ApplicationArguments 接口来帮助您访问这些参数。让我们来看看如何使用它。

在 myretro 包中创建一个名为 MyRetroConfiguration 的新类。请参阅列表 2-11。

package com.apress.myretro;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRetroConfiguration {
    Logger log = LoggerFactory.getLogger(MyretroApplication.class);
    MyRetroConfiguration(ApplicationArguments arguments){
            log.info("Option Arg Values: {}", arguments.getOptionValues("option"));
    }
}

列表 2-11 源代码:src/main/java/com/apress/myretro/MyRetroConfiguration.java

在 MyRetroConfiguration 类中,我们将使用并传递以下参数:

--enable --remote --option=value1 --option=value2 update upgrade

Option Args: [enable, remote, option]
Option Arg Values: [value1, value2]
Option: [update, upgrade]

让我们来分析一下列表 2-11 中的代码及其结果:

  • @Configuration: 自动配置会识别此注解,评估其内容,并确定(在此情况下)它有一个使用 ApplicationArguments 接口作为参数的构造函数。这个参数会在 Spring 应用程序生命周期中自动注入;在这种情况下,它会传递在主类中 .run(args) 方法调用时声明的 args。ApplicationArguments 接口提供了多种方法,可以帮助识别所有参数,包括带值的选项(用 -- 和 = 及其值表示)以及仅称为非选项参数的参数。
  • getOptionNames() 方法将获取所有通过 --<参数名称> 指定的选项。在这个例子中,这些选项是 enable、remote 和 option。
  • getOptionValues(String) 方法接受一个参数名称,该名称可以有一个或多个值,格式为 --=。在这个例子中,我们查找名为 option 的参数及其值,结果是 value1 和 value2(因为它出现了多次)。
  • getNonOptionArgs() 方法用于获取所有未用 -- 标记的参数(即仅常规参数)。在这个例子中,这些参数是 update 和 upgrade。

可执行的 JAR 文件

这个功能与您选择的任何依赖管理工具(如 Maven 或 Gradle)的 Spring Boot 插件更为相关。本书假设使用 Gradle。要在 build/libs 目录中创建可执行的 JAR,请运行以下命令:

./gradlew build

然后,你可以使用它来运行

java -jar build/libs/myretro-0.0.1-SNAPSHOT.jar

如果您想向您的 JAR 传递一些参数,可以执行以下命令:

java -jar build/libs/myretro-0.0.1-SNAPSHOT.jar --enable --remote --option=value1 --option=value2 update upgrade

你应该得到与之前相同的结果。

应用程序运行器、命令行运行器与应用程序准备就绪事件

作为开发者,我们需要在应用程序准备好接受任何请求或其他交互之前,启动一个过程或执行某些逻辑。Spring Boot 提供了多个接口和事件,允许我们在应用程序准备就绪之前执行代码。您可以将列表 2-12 中的代码添加到 MyRetroConfiguration 类中。

package com.apress.myretro;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
public class MyRetroConfiguration {
    Logger log = LoggerFactory.getLogger(MyretroApplication.class);
@Bean
        CommandLineRunner commandLineRunner(){
                return args -> {
                        log.info("[CLR] Args: {}",Arrays.toString(args));
                };
        }
        @Bean
        ApplicationRunner applicationRunner(){
            return args -> {
                    log.info("[AR] Option Args: {}", args.getOptionNames());
                    log.info("[AR] Option Arg Values: {}", args.getOptionValues("option"));
                    log.info("[AR] Non Option: {}",args.getNonOptionArgs());
            };
    }
    @Bean
    ApplicationListener<ApplicationReadyEvent> applicationReadyEventApplicationListener(){
            return event -> {
                    log.info("[AL] Im ready to interact...");
            };
    }
}

列表 2-12 源代码:src/main/java/com/apress/myretro/MyRetroConfiguration.java

正如您所看到的,我们已经去掉了构造函数,因为 ApplicationRunner 接口已经提供了应用程序参数。请注意,现在有一些方法被标记为 @Bean 注解,Spring Boot 的自动配置将利用这些方法来创建所需的 Spring bean。让我们来回顾一下代码。

  • CommandLineRunner:这个接口的实现将在 Spring 和 Spring Boot 完成所有配置后被调用。它是一个功能接口,包含一个回调(run 方法),用于接收传递给应用程序的参数。在这种情况下,结果是所有的参数。
  • 应用程序运行器:此接口的实现将在命令行运行器的实现之前被调用。它是一个函数式接口,包含一个回调(运行方法),该方法以应用程序参数作为参数,因此如果我们想使用这些参数,它是一个很好的选择。
  • 应用监听器: 当 Spring Boot 应用程序完成所有配置并准备好进行交互时,将触发此事件。因此,这个事件将是最后一个被调用的。

如果你按照之前的方式运行应用程序(使用相同的参数),你应该会看到以下输出:

...
[AR] Option Args: [enable, remote, option]
[AR] Option Arg Values: [value1, value2]
[AR] Non Option: [update, upgrade]
[CLR] Args: [--enable, --remote, --option=value1, --option=value2, update, upgrade]
[AL] Im ready to interact...
...

请注意,ApplicationRunner 首先被调用,然后是 CommandLineRunner,最后是 ApplicationReadyEvent。您可以有多个实现 run 方法的 CommandLineRunner 类,这些类必须标记为 @Component。如果需要按顺序列出,可以使用 @Order 注解(根据优先级,使用 Ordered 枚举作为参数)。

应用程序配置

有时候,我们需要对远程服务器进行非常具体的访问,或者需要连接远程服务器的凭据,甚至需要存储在数据库中的敏感数据。虽然我们可以将这些信息(凭据、远程 IP、敏感数据)硬编码,但这并不是最佳实践,因为这些信息可能会迅速变化,可能会导致我们在重新部署应用时出现错误,进而带来不良后果,比如连接到错误的服务器。

Spring Boot 使用 application.properties 或 application.yaml 来外部化所需的配置,同时也利用这些文件来覆盖应用程序中的一些默认设置(这与自动配置和条件有关)。在本书中,您将学习如何更改这些默认设置,但现在我们先来讨论如何创建自己的属性以及如何使用它们。

我的复古应用与用户应用项目的整合

为了了解如何使用外部配置,让我们继续我们的旅程,回顾我们的两个项目:我的复古应用和用户应用。尽管我们尚未讨论这些项目在本书中将如何集成,但在某个时刻,我的复古应用需要联系用户应用,以验证和授权希望使用我的复古应用的用户。因此,在这种情况下,必须拥有服务器、端口和其他有用的信息。

在我的复古应用程序中,打开 application.properties 文件,并添加列表 2-13 所示的内容。

# Users Properties
users.server=127.0.0.1
users.port=8081
users.username=admin
users.password=aW3s0m3

列表 2-13 源文件:src/main/java/resources/application.properties

列表 2-13 展示了我们在 My Retro App 项目中需要的一些属性。接下来,打开 MyRetroConfiguration 类,并将内容替换为列表 2-14 中提供的代码。

package com.apress.myretro;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRetroConfiguration {
    Logger log = LoggerFactory.getLogger(MyRetroConfiguration.class);
     @Value("${users.server}")
        String server;
        @Value("${users.port}")
        Integer port;
        @Value("${users.username}")
        String username;
        @Value("${users.password}")
        String password;
    @Bean
    ApplicationListener<ApplicationReadyEvent> init(){
        return event -> {
            log.info("\nThe users service properties are:\n- Server: {}\n- Port: {}\n- Username: {}\n- Password: {}",server,port,username,password);
        };
    }
}

列表 2-14 源代码:src/main/java/com/apress/myretro/MyRetroConfiguration.java

列表 2-14 展示了更新后的 MyRetroConfiguration 类。我们来分析一下。

  • 这是一个新的注解,用于收集在“”之间指定的属性值,使用以$开头的 SpEL(Spring 表达式语言)和{}中的属性名称。在 Spring 应用程序的生命周期中(收集信息和创建 bean),它会查找所有@Value 注解,并尝试在默认文件 application.properties 或 application.yaml 中查找相应的值。例如,我们声明了一个 Integer 类型的 port 变量,并用@Value("${users.port}")注解它,因此在这个类实例化时,它将获取值 8081 并赋值给 port 变量。
  • 应用监听器:当 ApplicationReadyEvent 被触发时,此接口将执行 init 方法(这表示应用程序已准备好与其他逻辑进行交互)。

如果你运行这个应用程序,你应该会看到类似于以下的输出:

The users service properties are:
- Server: 127.0.0.1
- Port: 8081
- Username: admin
- Password: aW3s0m3

现在,如果我们有超过四个属性会发生什么呢?我们可以添加更多变量并用@Value 进行标记,但这样很快就会变得混乱。Spring Boot 在这种情况下提供了更好的解决方案,接下来将进行介绍。

配置选项

Spring Boot 提供了一个简单的解决方案来处理多个和更复杂的属性。它定义了一个类标记 @ConfigurationProperties 注解,将类的字段与外部定义的属性(在我们的例子中是 application.properties)绑定。

让我们在 src/main/java/com/apress/myretro 文件夹中创建一个名为 MyRetroProperties 的新类,内容如清单 2-15 所示。

package com.apress.myretro;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties
public class MyRetroProperties {
    Users users;
    public Users getUsers() {
        return users;
    }
    public void setUsers(Users users) {
        this.users = users;
    }
}
class Users {
    String server;
    Integer port;
    String username;
    String password;
    public String getServer() {
        return server;
    }
    public void setServer(String server) {
        this.server = server;
    }
    public Integer getPort() {
        return port;
    }
    public void setPort(Integer port) {
        this.port = port;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

列表 2-15 源代码:src/main/java/com/apress/myretro/MyRetroProperties.java

列表 2-15 展示了 MyRetroProperties 类,得益于@ConfigurationProperties,它将 application.properties(或 application.yaml)中的属性绑定到该类的每个字段。请注意,这个类只是一个 POJO(普通旧 Java 对象),包含 setter 和 getter 方法。其设计理念是每个字段的名称相同,以便能够匹配。为了告诉 Spring Boot 这个类是一个 ConfigurationProperties 类,我们需要通过将类标记为@Component 或在 Configuration 类中使用@EnableConfigurationProperties 注解来进行说明。列表 2-16 展示了修改后的 MyRetroConfiguration 类。

package com.apress.myretro;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties({MyRetroProperties.class})
@Configuration
public class MyRetroConfiguration {
    Logger log = LoggerFactory.getLogger(MyRetroConfiguration.class);
    @Bean
    ApplicationListener<ApplicationReadyEvent> init(MyRetroProperties myRetroProperties){
        return event -> {
            log.info("\nThe users service properties are:\n- Server: {}\n- Port: {}\n- Username: {}\n- Password: {}",
                    myRetroProperties.getUsers().getServer(),
                    myRetroProperties.getUsers().getPort(),
                    myRetroProperties.getUsers().getUsername(),
                    myRetroProperties.getUsers().getPassword());
        };
    }
}

列表 2-16 源代码:src/main/java/com/apress/myretro/MyRetroConfiguration.java

在修改后的 MyRetroConfiguration 类中,我们使用了 @EnableConfigurationProperties 注解,该注解接受一个标记为 ConfigurationProperties 的类数组。此外,请注意,init 方法现在有一个 MyRetroProperties 参数,这个类(MyRetroConfiguration.class)将由 Spring 自动注入(因为它使用 @Bean 注解标记)。这样,您可以像访问其他常规类一样,通过其 getter 方法来访问这些属性。

如果我们有多个服务(不仅仅是用户),会发生什么呢?将它们标识为服务会很好,对吧?这意味着我们可以在配置属性类中添加一个前缀。请看下一个代码片段。

@ConfigurationProperties(prefix="service")
public class MyRetroProperties {
    Users users;
    public Users getUsers() {
        return users;
    }
    public void setUsers(Users users) {
        this.users = users;
    }
}

前缀参数将根据您在属性文件中设置的内容,使用服务.* 属性进行绑定匹配。这意味着我们的 application.properties 文件应该如下所示:

service.users.server=127.0.0.1
service.users.port=8081
service.users.username=admin
service.users.password=aW3s0m3

如果你运行这个应用程序,应该会得到相同的结果。

轻松的绑定

我之前提到过,属性名称必须与类中的字段名称一致,对吗?那么,Spring Boot 提供了一种宽松的绑定方式;它为将环境属性绑定到标记为 @ConfigurationProperties 的类提供了一些宽松的规则。如果你的字段名是过长的驼峰命名,你可以使用驼峰命名、下划线、短横线或大写格式。请考虑以下示例:

private String hostNameServer;

你可以使用以下表示法:

  • 驼峰命名:hostNameServer
  • 主机名: host-name-server
  • 下划线:host_name_server
  • 大写: HOST_NAME_SERVER

配置的优先级

使用外部化配置的另一个好处是可以通过不同的方式来定义属性。您可以使用环境变量、Java 系统属性、JNDI、servlet 内容、配置参数、命令行参数等多种方式。但是,如果我在所有这些机制中都定义了相同的属性,会发生什么呢?好消息是,Spring Boot 在运行应用程序时有一些优先级规则可以遵循。

以下列表展示了在运行您的应用程序及其属性绑定时将遵循的优先级顺序:

  • 默认属性(由 SpringApplication.setDefaultProperties 设置)。
  • @Configuration 类中的@PropertySource 注解。请注意,这些属性源在应用程序上下文刷新之前不会被添加到环境中。因此,对于某些属性(如 logging.*和 spring.main.*)的配置来说,这个时机已经太晚,因为它们在刷新开始之前就会被读取。
  • 配置数据(如 application.properties 文件)。
  • 一个仅在 random.* 中包含属性的 RandomValuePropertySource。
  • 操作系统的环境变量。
  • Java 系统属性(通过 System.getProperties() 获取)。
  • 来自 java:comp/env 的 JNDI 属性。
  • ServletContext 的初始化参数。
  • ServletConfig 的初始化参数。
  • 来自 SPRING_APPLICATION_JSON 的属性(嵌入在环境变量或系统属性中的 JSON)。
  • 命令行选项。
  • 您的测试中的属性(可在@SpringBootTest 和用于测试应用程序特定部分的测试注解中使用)。
  • 在测试中使用@TestPropertySource 注解。
  • 当开发工具处于活动状态时,$HOME/.config/spring-boot 目录下的开发工具全局设置属性。

使用 application.properties 文件时,您可以遵循以下优先级:

  • 打包在您的 JAR 文件中的应用程序属性(application.properties 和 YAML 格式)
  • 打包在您的 JAR 文件中的特定于配置文件的应用程序属性(application-{profile}.properties 和 YAML 格式)
  • 应用程序属性文件位于您的打包 JAR 之外(包括 application.properties 和 YAML 格式)
  • 针对特定配置文件的应用程序属性应放在打包的 JAR 文件之外(application-{profile}.properties 和 YAML 变体)

当然,有很多选项可以使用外部配置,您甚至可以通过以下属性/参数来指定读取文件的位置:--spring.config.location=。我认为这里最重要的是关注优先级。总结一下,如果您有一个包含 application.properties 的 JAR 文件,而您运行应用程序的地方有另一个同名文件,那么这个文件将覆盖您已有的配置,任何环境变量也会覆盖 JAR 应用程序中的属性。

修改默认设置

正如您所知,Spring Boot 使用默认设置来配置您的应用程序,但有时这些默认设置并不符合您的需求。Spring Boot 的一个重要特性是可以更改这些默认设置。您已经看到可以通过在 @SpringBootApplication 注解中使用 exclude={} 参数来排除某些自动配置。此外,还有一种方法可以指定您希望如何更改这些默认设置。

这里有一个重要的应用程序属性列表,您可以在此链接访问:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html。例如,如果您想将默认端口 8080 更改为 8082,可以使用属性 server.port=8082。

以下命令可以达到相同的效果:


java -jar build/libs/myretro-0.0.1-SNAPSHOT.jar --server.port=8082
SERVER_POST=8082  java -jar build/libs/myretro-0.0.1-SNAPSHOT.jar
java -Dspring.application.json='{"server.port":8082}' -jar build/libs/myretro-0.0.1-SNAPSHOT.jar

应用程序档案

Spring Boot 也支持处理配置文件,这意味着您不仅可以使用自定义属性或覆盖默认设置,还可以利用配置文件来创建 bean。在接下来的章节中,我们将讨论 Spring Profile。

正如您之前看到的,您可以创建 application-.properties(或 YAML 文件)。当您有多个环境并希望为每个环境跟踪不同的值时,这非常方便。要使用这些功能,您需要通过 SpringApplicationBuilder.profiles(如您之前所见)或通过设置属性 spring.profiles.active= 来激活配置文件。

例如,您可以在资源文件夹中创建一个额外的 application-cloud.properties 文件,并添加其他值:

service.users.server=cloud.server.com
service.users.port=1089
service.users.username=root
service.users.password=Sup3RaW3s0m3

如果您通过命令行或您喜欢的 IDE 传递属性来运行应用程序

--spring.profiles.active="cloud"

你应该只查看 application-cloud.properties 文件中的值。

使用 YAML 格式可以通过只用一个文件来简化属性。例如,application.yaml 文件可以是这样的:

service:
  users:
    server: 127.0.0.1
    port: 8081
    username: admin
    password: aW3s0m3
---
spring:
  config:
    activate:
      on-profile: cloud
service:
  users:

概要

本章介绍了许多功能,重点关注最重要的部分,或者说大多数开发者会使用的功能。你了解了 Spring Boot 的内部机制,并发现 Spring Boot 通过自动配置功能来设置默认值,这些默认值结合了应用程序的最佳实践。你还了解到,Spring Boot 会通过自动配置功能检查你的应用程序所使用的依赖项或类路径,并决定应用哪些默认值。所有这些都得益于自动配置类和@Conditional*注解,这些注解帮助过滤出应用程序所需的内容以及如何连接各个部分,从而减少了在创建 Spring 应用程序时通常需要进行的配置工作。

本章还向您展示了如何通过使用 SpringApplication 类或 SpringApplicationBuilder 流式 API 来定制您的 Spring Boot 应用程序。您还了解了如何在应用程序中使用参数,以及如何设置和使用 application.properties,甚至可以通过配置文件对其进行过滤。

在第三章中,我们将讨论如何使用 Spring Boot 开发 Web 应用,并通过我们的 My Retro App 和 Users App 项目创建 Web 端点。

相关推荐

攀升战境S5电竞主机评测:NVIDIA RTX 3060实力助阵,光追游戏走起

此次笔者将为玩家们推荐一款游戏主机——攀升战境S5。该主机是攀升电脑今年力推的游戏装备,主机采用一线品牌配件,特别是在显卡选用上严苛把关,精选GeForceRTX30系列显卡,玩家们大可以放心选购...

慎买-神牛闪光灯兼容性问题:神牛V350&amp;松下S5M2

神牛V350和松下S5M2的兼容性问题。大家好,我是向往闪光灯人像的Fish。国庆期间,我购买了神牛V350闪光灯和神牛X2T引闪器,但这成为了我的噩梦。我原以为客服和松友们说这款闪光灯在松下S5M2...

Acer蜂鸟持续办公一整天(acer 蜂鸟s5)

移动办公在工作节奏日益加快的今天越来越普遍,目前大部分工作无法在手持设备上完成,笔记本依然是移动办公最明智的选择。为了实现移动办公,很多笔记本越做越轻薄,性能也越来越强,而续航却一直没有很大提升。笔者...

职业车手明年会骑什么?2021赛季各大世巡赛车队使用器材一览

新年的钟声即将敲响,意味着充满魔幻色彩的2020年即将过去。受新冠肺炎的影响,2020年的赛季非常不同寻常。因这一原因不得不延迟举行的各种比赛导致许多车队的赞助商无法得到足够曝光,这也间接导致了许多车...

三星部分手机系统升级路线图流出(三星系统在哪升级)

三星包括Note3和S5在内的手机在升级到4.4.2系统之后一直没有什么系统升级的消息,而最近流出的一张三星的系统升级路线图中出现了一共13台手机升级KTU84P(也就是Android4.4.4)...

索尼Xperia Z3配置大曝光:升级并不大

IT之家(www.ithome.com):索尼XperiaZ3配置大曝光:升级并不大索尼明天就会在IFA2014大会上发布其下代旗舰XperiaZ3智能手机,目前网上曝光了其原型机,并且机身背后...

不进反退 三星Exynos 5433只能运行32位模式?

三星GalaxyNote4将带有两个版本,除了国行使用的骁龙805以外,还有三星自家的Exynos5433版本。而这颗SoC的详细信息三星并没有公布,据外媒Anandtech称,他们从源码中确认...

尼康Z6III测评:对比EOS R6 II、A7M4、S5IIX

摄影器材测评网站DPReview刚刚发布了尼康Z6III的完整图文测评,该机获得金奖评级,得分达到91%。以下是该文章的摘录——尼康Z6III核心规格:2400万像素“部分堆栈式”传感器RAW连拍:机...

赛默飞Ion S5首批数据公布,玩爆前任PGMTM系列

北美时间9月1日,赛默飞发布了两款最新的NGS系统IonS5和IonS5XL,旨在提供更加简捷的靶向测序流程。10月29日IonS5测序仪的首批实验数据产生于阜外医院。阜外医院研究人员选用了主...

Excel技巧:快速制作批量文件夹,省时省力,加强工作效率

大家好,如果公司领导要求按人员姓名制作文件夹,以一人一档的形式呈现人员档案,办公人员一个一个制作费时费力,而且效力低下,今天为大家介绍快捷制作批量文件夹的方法下面我们用图片来进行演示操作打开表格,选...

国行、港版、美版Apple watch各版本售价一览

今天凌晨,苹果牌手表正式发布,苹果开始正式进入可穿戴设备领域,除了功能和外观,我相信大家更关心的是价格问题了,小编就将国行、港版、美版的Applewatch售价做一总结,以供参考。国行:美版:港版:...

松下全画幅微单S5和S1到底哪里不一样?

Hello,我是ET,欢迎大家来到我的“相机笔记”。————9月2日晚,松下正式发布了第4款全画幅微单LUMIXS5。这一篇,我们主要来说松下LUMIXS5和LUMIXS1到底有哪些区别...

融会贯通之典范 神舟S7-2021S5评测

便携、性能、续航,这简简单单的六个字道出了这么些年来笔记本电脑的设计方向,可是由于底层技术、模具设计等等原因,这三点并不能很好的融合在一起。虽说闻道有先后,术业有专攻,但能够有一台融会贯通的产品,不是...

三国志战略版:S5赛季装X指南,开荒不是一成不变,需要因地制宜

大家好我是零氪玩家花席,S5赛季已经开始,因为S5赛季的野地阵容和S4赛季没有区别,所以S5赛季开荒相对不难。你在S4有经验,并且多了很多武将和战法,还能用150赛季功勋兑换7500战法点。S5赛季新...

聊聊松下S5M2和S5M2X的区别(松下s5k和s5c有什么区别)

先简单说下哪里不同:12bitRAWHDMI外录支持直接将视频录制到USB-SSD上多了All-Intra和ProRes编码支持有线/无线IP推流,USB网络连接黑化的机身不过要特别强调一下,S5...