首页 > 编程笔记

Spring Boot配置详解

我们听过 Spring Boot 的“自动配置”,那么自动配置大概在做什么?如果程序有更多的自定义配置的需求,在 Spring Boot 开发的过程中又需要做什么?本文会对这些内容做一个基本介绍。

自动配置

有读者可能会问:自动配置,自动在哪?答案并不复杂。Spring Boot 的自动配置会在没有自定义配置的情况下,尝试根据现有的 jar 包依赖对程序进行配置。在不做任何配置的情况下启动项目。输入以下命令以使用 Spring-Boot Maven 插件运行 Spring Boot 项目:

mvn spring-boot:run

程序成功启动之后,终端程序上将打印如下日志信息:

Using dialect: org.hibernate.dialect.H2Dialect

看到了这行日志,说明程序已自动将 H2 数据库作为默认数据源配置在项目中了。

外部配置

自动配置能简化开发流程,但在真实的开发情景下还是需要开发人员手动进行配置才能满足多种多样的需求。Spring Boot 提供了多种途径的外部配置来协助开发人员,以便于在不同环境能使用相同的代码。使用 properties 文件、yaml 文件、环境变量和命令行参数,结合 @Value 与 @ConfigurationProperties 等注解,将配置的值注入到程序当中。

为了将外部配置和自动配置配合使用,Spring Boot 为这些配置的加载指定了一个顺序:
  1. Devtools 全局配置文件,路径:~/.spring-boot-devtools.properties(当 Spring Boot Devtools 启用)。
  2. 测试用例中的“@TestPropertySource”注解。
  3. 测试用例中的“properties”属性。在 @SpringBootTest 和测试注解上可用,用于测试应用程序的特定部分。
  4. 命令行参数。
  5. 环境变量“SPRING_APPLICATION_JSON”中的字段。
  6. “ServletConfig”初始化参数。
  7. “ServletContext”初始化参数。
  8. “java:comp/env”中的 JNDI 参数。
  9. Java 系统属性 (System.getProperties())。
  10. 系统环境变量。
  11. 配置文件“RandomValuePropertySource”,该配置文件都是随机的(random.*)。
  12. 打包文件外包含于特定 profile 的配置文件(application-{profile}.propertie-s/yaml)。
  13. 打包文件内包含于特定 profile 的配置文件(application-{profile}.propertie-s/yaml)。
  14. 打包文件外的配置文件(application.properties/yaml)。
  15. 打包文件内的配置文件(application.properties/yaml)。
  16. 配置在 @Configuration 配置文件中的“@PropertySource”注解。
  17. 默认配置。通过 SpringApplication.setDefaultProperties() 配置的属性。

命令行配置

上面的介绍中可以了解到,命令行配置的优先级相对来说还是比较高的。通过“--”符号声明配置项,比如 --server.port=9000 可以配置服务的端口。在IDEA 的配置项中,打开启动项配置页“Run/Debug Configuration”,在 Program arguments 栏将配置内容输入即可在启动时附上配置项,如图 1 所示。
图1 启动配置页
图1 启动配置页

application.yaml/properties配置文件

application.yaml/properties 配置文件是相对来说更常用的配置方式,配合各类注解可以满足不同需求的场景。application 配置文件支持三种格式:
优先级分别为 properties→yml→yaml。在配置文件内部的优先级为自下而上进行覆盖。虽然 Spring Boot 有这样的机制,但不建议创建多个不同格式的application 配置文件,并且配置文件内的配置项务必保持唯一,否则项目的维护将是一场灾难。

推荐使用 yaml 格式的 application.yml 文件进行配置。相较 application.properties 来说,application.yml 采用的 yaml 格式层级关系更为鲜明,使用起来更为方便。

application.properties 样例:

server.port = 8080

logging.path = /var/logs
logging.file = myapp.log
logging.config = # 此行填入配置文件路径( defaule classpath:logback.xml )
logging.level.* = # 此行填入 loggers 等级, e.g."logging.level.org.springframework=DEBUG"( TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF )

application.yml 样例:

server:
    port:8080

logging:
    path: /var/logs
    file: myapp.log
    config:   #此行填入配置文件路径(default classpath:logback.xml)
    level.*:   # 此行填入 loggers 等级, e.g."logging.level.org.springframework=DEBUG"( TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF )

结合 @ConfigurationProperties 注解可以将对程序内变量的赋值提取到配置文件中。在路径 src/main/java/com/example/myblog/config 下创建BlogProperties.java :
@Configurationproperties("blog")
public class BlogProperties {

    private String title;
    private Banner banner;
    //省略了字段的getter与settera
}
在 BlogApplication 中启用该配置:
@SpringBootApplication
@EnableConfigurationproperties(BlogProperties.class)

public class BlogApplication {
    //...
}
在路径 src/main/resources 路径下删除初始化的 application.properties 文件,并创建 application.yml 以替代它:

blog:
    title:Blog
    banner:
        title:surprise!
    contnet: You made it!!!

修改模板以及控制器,以用上这些配置属性。blog.mustache:

{{>header}}

<div class="articles">
        {{#banner.title}}
            <section>
                <header class="banner">
                    <h2 class="banner-titleH>{{banner.title}}</h2>
                </header>
                <div class="banner-content">
                    {{banner.content}}
                </div>
            </section>
        {{/banner.title}}

        {{#articles}}
            <section>
                <header class="article-header">
                    <h2 class="article-titie"><a href="/article/{{slug}}">{{title}}</a></h2>
                    <div class="article-meta">By<strong>{{author.firstName}}</strong>,on<strong>{{addedAt}}</strong></div>
                </header>
                <div class="article-description">
                    {{headline}}
                </div>
            </section>

        {{/articles}}
</div>

{{>footer}}

HtmlController.java:
@Controller
public class HtmlController {
    //...
    @GetMapping("/")
    public String blog(Model model) {
        model.addAttribute("title", blogProperties.getTitle());
        model.addAttribute("banner", blogProperties.getBanner());
        model.addAttribute("articles", StreamSupport.stream(repository, findAllByOrderByAddedAtDesc().spliterator(), true).map(this::render).collect(Collectors.toList()));
        return "blog";
    }
    //......
}
重启应用后,可以看到新的主页标题和内容了。

优秀文章