Properties-and-Configuration

在学习Properties和Configuration之前,我们先要熟悉spring框架。可以从springinitialzr拉一个框架来观察。这里建议在跟教程的时候多写几个简单的项目,这样框架就会自然而然熟悉起来。
这里我把maven编译的spring项目架构画了在这里。

springboot 项目架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
demo
├── .mvn (放 maven-wrapper.properties)
├── src
│ ├── main (生产)
│ │ ├── java (\com\example\demo 放 .java 文件)
│ │ └── resources ─────────────────────────────┐
│ │ ├── static │
│ │ ├── templates (放 .html、.jsp 模板) │(编译、拷贝)
│ │ └── application.yml (或 .properties) │
│ └── test (测试) │
├── target │
│ ├── classes ◄──────────────────────────────────┘
│ │ ├── com (放编译后的 .class 文件)
│ │ ├── templates (放模板)
│ │ └── application.yml (properties) 占位符替换
│ ├── generated-sources
│ ├── maven-status
│ └── test-classes
├── pom.xml
└── 其他文件:.gitignore / .gitattributes / .mvnw / .mvnw.cmd 等


在熟悉框架之后进入我们的学习,这次学习的内容是guide中的Properties and Configuration ,觉得看完这篇blog还不是很清楚的可以看下原文.

原文链接:https://docs.spring.io/spring-boot/how-to/properties-and-configuration.html

接下来会从6个部分讲解properties和configuration是如何被spring 使用的。


part1: maven资源展开(限制条件:生产环境即源码 main 中,test 中不行)

资源过滤

  1. 在 application.yml / properties 中,常用 @ @ 占位符来避免硬编码,是从已解析的 pom.xml 中找到占位键对应的值,进行替换后写入 target / classes 中的 application.yml。例如在 src 中 application.properties 中写 version = @project.version@ 替换。

  2. 展开属性,也就是占位符的替换,是由 maven 在编译、打包期间进行的。maven-resources-plugin 是执行者,这个插件是 pom.xml <parent> 中配置 spring-boot-starter 就自带的。常在 pom.xml<parent>自带的。

    Tips:如果不用 starter-parent 需要在prom.xml中添加相关内容

  3. 展开属性失效:当开启 addResources 标识的时候,开启 addResources 的同时,也开启了热重载(hot reloading),将 src/main/resources 挂载到运行的 classpath 上

TIP:这里的挂载是什么?有什么效果?
正常(非挂载状态下),Java 程序运行只能读取 target / classes(即编译后的目录)中的文件,如果在程序运行时修改源码,程序并不能直接展现变化,必须再次经过一次 maven 编译和拷贝更新。
而挂载则是将源码路径 src/main/resources 追加到 classpath 上,使得源码修改可以立刻生效,而无需编译,便于开发。


part2: 使用外部配置控制 Spring Application

使用外部配置控制指的是 application.properties / yml
Spring Application 中修改配置使用 Java API。

这里教程说到:application.properties 中可以使用 spring.main.* 来改变 spring Application 的一些配置,被称为外部化配置(实质是配置的映射),而与此相对的,写在 Application 中的则是硬编码。

例如,以下的代码在properties中关闭了打印 spring banner 的配置

1
2
spring.main.banner-mode = off

既然这里说到application.properties / yml可以通过 Spring Application 映射的 spring.main.* 修改属性,则我们可以发现两种设置存在优先级:外部配置 > Java API

普通配置项(如 Banner、Web类型、port 等)遵循这个优先级,是 Java API < 外部配置

但存在例外:主配置源(primary sources)

TIP:何为主配置源根据官方定义,primary sources 是指传给SpringApplication构造函数(或SpringApplicationBuilder.sources()方法)的那些 class 类或 package,它们是用于引导和创建 spring 应用上下文的顶级配置起点(ApplicationContext)。 主配置源可以有多个,但一般只传一个主类(即有 main() 并有@SpringBootApplication的那个类)。 主配置源通常贴着@SpringBootApplication` 注解,是整个 Spring 容器的艮起点。
一般来说长这样:

1
2
3
4
// MyApplication.class 是主配置源
SpringApplication application = new SpringApplication(MyApplication.class);
application.run(args);


part3:修改应用外部属性的位置

这个标题在第一次看到时会觉得一头雾水,实际上,这一部分讲的是如何让 Spring Boot 正确读取自定义配置文件,以及给出了配置不生效时(也就是读取失败时)如何通过日志排查。

我们都用过 spring initializr 拉过 spring 框架,也都知道外部配置 application.properties / yml 中读取配置的(Spring 默认从…)。但在实际生产中,我们可能会修改 .yml 文件名称或位置。

举一个大家都遇到过的问题——模版接入的 api key 注入,这些配置出于安全考虑,都会直接写在项目的外部配置中。因此,如何让 Spring 读到这些应用外部属性呢?

一般是通过命令行 / 系统属性 / 环境变量在程序启动时修改两个参数:spring.config.namespring.config.location
前者适用于仅修改名称而文件读取路径不变的情况,后者直接修改查找路径。

1
2
3
java -jar app.jar --spring.config.name=myapp
java -jar app.jar --spring.config.location=file:/etc/myapp/config.yml

为什么通过外部环境传入?
因为读取配置文件之前就需要知悉文件读取路径,只有命令行 / 系统属性 / 环境变量可以做到。

排查配置不生效的方法:trace 日志
官方提供的排查方法如下:

1
2
java -jar app.jar --logging.level.org.springframework.boot.context.config=true


part4:使用“简短”的 cmd 参数

这里介绍的是 port 的简短配置方式,操作方式是:
application.properties / yml 中:

1
server.port = ${port:8080}

TIP:这里的${变量名 :默认值}

这样 port 在命令行中就可代替 server.port,并且有了默认值 8080。
这样做也使得在 Docker、Heroku 等平台部署更方便,因为在 PaaS 环境中分配端口注入方式为 PORT,也就可以被正确识别为 server.port 并注入。


part5:使用 YAML 作为外部属性配置

yaml 是 json 的超集,不难看出两者格式与语法区别很相似。

1
2
3
4
5
6
7
# yaml
server:
port: 8080
active: true
tags:
- java
- spring
1
2
3
4
5
6
7
8
9
10
11
# json
{
"server": {
"port": 8080,
"active": true
},
"tags": [
"java",
"spring"
]
}

.yaml 解析所需依赖包含在 spring-boot-starter 中。解析后由树状变为如 properties 一样的单层,生成以 . 分隔的键。

由于 yaml 树状结构清晰,一般复杂项目都会采用 yaml,而不是 properties。


part6:设置激活的 Spring Profile

什么是 profile,我们为什么要激活它?

profile 是 spring 框架提供的一种环境隔离机制,它允许开发者把针对不同运行环境的配置和组件分隔开,当某一 profile 被激活,对应的配置和组件才会生效。

在开发过程中,我们需要在不同环境中运行一套代码,通常会有:dev 开发环境 prod 生产环境 。这些环境的数据库连接、日志级别、API 注入方式等都会存在很大差异,而每次手动修改配置则很容易出错也很吃力。于是我们引入了profile,便于快速切换环境。

那profile具体要怎么写,写在哪里呢?

profile 是由 Java 代码与配置文件共同完成的

在 Java 代码中,一般用于加载组件

1
2
3
4
5
6
7
8
9
@Service
@Profile("dev")
public class MockPaymentService implements PaymentService { ... }
// 表示当激活 dev 环境时,才注册 MockPaymentService 对象为组件

@Service
@Profile("prod")
public class AlipayService implements PaymentService { ... }

在配置文件中一般控制配置参数具体数值:

1
2
3
4
5
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev-db

当激活某一 profile 时,相关的 Java 代码和配置文件(包括通用的 application.yml 与对应的 application-profile.yml )会被激活。

这里配置文件划分 profile有两种方式:

  1. 第一种是分为多个 yml 文件:
  • application.yml — 通用
  • application-dev.yml — 不同 profile
  • application-prod.yml
  1. 第二种是 application.yml 中用 #--- 分区。例如:
1
2
3
4
5
6
7
8
9
# properties
server.port = 8080
#---
spring.config.activate.on-profile = development
server.port = 8081
#---
spring.config.activate.on-profile = production
server.port = 0

其中激活的 profile 设置可覆盖默认。

那如何激活 profile 呢?

在启动程序时指定激活命令,如:

1
2
--spring.profiles.active=prod

default profile 如何设置呢?

application.properties 中可设置 default profile:

1
2
spring.profiles.default=dev


学到这里,我们已经读完了官方教程的大部分内容,对于Configuration和Properties也有了大致的认识和掌握!关于具体如何写,在下一次笔记中会写到。


Commentarii · 评论