《spring实战》学习笔记 第5章 使用配置属性

5. 1   细 粒度 的 自动 配置

Spring 中有 两种 不同( 但 相关) 的 配置。

  • bean 装配: 声明 在 Spring 应用 上下 文中 创建 哪些应用 组件 以及 它们 之间 如何 互相 注入 的 配置。
  • 属性 注入: 设置 Spring 应用 上下 文中 bean 的 值 的 配置。

 

在 Spring 的 XML 方式 和 基于 Java 的 配置 中, 这 两种 类型 的 配置 通常 会在 同一个 地方 显 式 声明。(配置文件)

在 基于 Java 的 配置 中, 带有@ Bean 注解 的 方法 一般 会 同时 初始化 bean 并立 即为 它的 属性 设置 值。(代码注解)

5. 1. 1   理解 Spring 的 环境 抽象

Spring 环境 会 拉 取 多个 属性 源, 包括:

  • JVM 系统 属性;
  • 操作系统 环境 变量;
  • 命令行 参数;
  • 应用 属性 配置文件。

 

它 会 将 这些 属性 聚合 到 一个 源 中, 通过 这个 源 可以 注入 到 Spring 的 bean 中。

 

Spring Boot 自动 配置 的 bean 都可以 通过 Spring 环境 提取 的 属性 进行 配置。 举个 简单 的 例子, 假设 我们 希望 应用 底层 的 Servlet 容器 使用 另外 一个 端口 监听 请求, 而 不再 使用 8080。

 

我们 可以 在“ src/ main/ resources/ application. properties” 中将 server. port 设置 成 一个 不同 的 端口,

server. port= 909

也可以在“ src/ main/ resources/ application. yml” 中 设置 server. port 的 值,

server: port: 
     9090

如果 你 喜欢 在外 部 配置 该 属性, 那么 可以 在 使用 命令行 参数 启动 应用 的 时候 指定 端口:

$ java -jar tacocloud-0.0.5-SNAPSHOT.jar --server.port=9090

如果 你 希望 应用 始终 在 一个 特定 的 端口 启动, 那么 可以 通过 操作系统 的 环境 变量 进行 一次 性的 设置:

$ export SERVER_ PORT= 9090

 

上面这些配置的效果都是一样的

 

5. 1. 2   配置 数据 源

如果 你想 要 开始 使用 MySQL 数据库,

spring:
  datasource:
    url: jdbc:mysql://localhost/tacocloud
    username: tacouser
    password: tacopassword

如果 在 类 路径 中 存在 Tomcat 的 JDBC 连接 池, DataSource 将 使用 该 连接 池。 否则, Spring Boot 将 会在 类 路径 下 尝试 查找 并使 用 如下 的 连接 池 实现:

  • HikariCP
  • Commons DBCP 2

 

 

5. 1. 3   配置 嵌入 式 服务器

我们 已经 看到 过 如何 使用 server. port 属性 来 配置 servlet 容器 的 端口。 但是, 我还 没有 展示 将 server. port 设置 为 0 将会 出现 什么 状况:

server:

    port: 0

尽管 我们将 server. port 属性 显 式 设置 成了 0, 但是 服务器 并不 会 真的 在 端口 0 上 启动。 相反, 它 会 任选 一个 可用 的 端口。 在 我们 运行 自动化 集成 测试 的 时候, 这 会 非常 有用, 因为 这样 能够 保证 并发 运行 的 测试 不会 与 硬 编码 的 端口 号 冲突。

 

 

这里有一部分,关于java配置生成HTTPS证书部分的内容,我觉得挺有用的,但是我没试过,仅做记录:

我们 对 底层 容器 常见 的 一项 设置 就是 让 它 处理 HTTPS 请求。 为了 实现 这一点, 我们 首先 要 使用 JDK 的 keytool 命令行 工具 生成 keystore:

$ keytool -keystore mykeys. jks -genkey -alias tomcat -keyalg RSA

在 这个 过程中, 会 询问 我们 一些 关于 名称 和 组织 机构 相关 的 问题, 大多数 问题 都 无关紧要。 但是, 它 提示 输入 密码 的 时候 需要 记住 你 所 选择 的 密码。 在 本例 中, 我 选择 使用 letmein 作为 密码。

接下来, 我们 需要 设置 一些 属性, 以 便于 在 嵌入 式 服务器 中 启用 HTTPS。 我们 可以 在 命令 行中 进行 配置,但是 这种 方式 非常 不方便, 相反, 你 可能 更 愿意 通过 application. properties 或 application. yml 文件 来 声明 配置。 在 application. yml 中, 配置 属性 如下 所示:

server:
    port:8443
    ssl:
        key-store:file:///path/to/mykeys.jks
        key-store-password:letmein
        key-password:letmein

在这里, 我们将 server. port 设置 为 8443, 这是 在开 发 阶段 HTTPS 服务器 的 常用 选择。 server. ssl. key- store 属性 应该 设置 为 我们 所 创建 的 keystore 文件 的 路径。 在这里, 它 使用 了 file:// URL, 因此 会在 文件 系统 中 加载, 但是, 如果 你 需要 将它 打包 到 一个 应用 JAR 文件 中, 就 需要 使用“ classpath:” URL 来 引用 它。 server. ssl. key- store- password 和 server. ssl. key- password 属性 都 设置 成了 创建 keystore 时 所 设置 的 密码。

 

结束HTTPS部分

 

5. 1. 4   配置 日志

默认 情况下, Spring Boot 通过 Logback 配置 日志, 日志 会 以 INFO 级别 写入 到 控制 台中。

为了 完全 控制 日志 的 配置, 我们 可 以在 类 路径 的 根 目录 下( 在 src/ main/ resources 中) 创建 一个 logback. xml 文件。

如下 是一 个 简单 logback. xml 文件 的 样 例:

<configuration>   
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">    
    <encoder>   
      <pattern>   
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n  
      </pattern>   
    </encoder>   
  </appender>   
  <logger name="root" level="INFO"/>
  <root level="INFO">   
    <appender-ref ref="STDOUT" />   
  </root>   
</configuration>   

在 日志 配置 方面, 你 可能 遇到 的 常见 变更 就是 修改 日志 级别 和 指定 日志 写入 到 哪个 文件 中。 借助 Spring Boot 的 配置 属性 功能, 我们 不用 创建 logback. xml 文件 就能 完成 这些 变更。

要 设置 日志 级别, 我们 可以 创建 以 logging. level 作为 前缀 的 属性, 随后 紧 跟着 的 是我 们 想要 设置 日志 级别 的 logger。

logging:
    level:
        root: WARN
        org.springframework.security: DEBUG

现在, 假设 我们 想要 将 日志 条目 写入 到“/ var/ logs/” 中的 TacoCloud. log 文件 中。 logging. path 和 logging. file 文件 可以 按照 如下 形式 进行 设置:

logging:
    path: /var/logs/ 
    file: TacoCloud.log
    level:
        root: WARN
        org.springframework.security: DEBUG

5. 1. 5   使用 特定 的 属性 值

在 设置 属性 的 时候, 我们 并非 必须 要将 它们 的 值 设置 为 硬 编码 的 String 或 数值。 其实, 我们 还可以 从其 他的 配置 属性 派生 值。

例如, 假设( 不管 基于 什么 原因) 我们 想要 设置 一个 名为 greeting. welcome 的 属性, 它的 值 来源于 名为 spring. application. name 的 另一个 属性。 为了 实现 该 功能, 在 设置 greeting. welcome 的 时候, 我们 可以 使用${} 占位符 标记:

greeting: 
    welcome: ${spring.application.name}

 

我们 甚至 可以 将 占位符 嵌入 到 其他 文本 中:

greeting: 
    welcome: You are using ${spring.application.name}.

总之 配置 属性 并不 专 属于 Spring 创建 的 bean。

 

 

5. 2   创建 自己的 配置 属性

 

为了 支持 配置 属性 的 注入, Spring Boot 提供 了@ ConfigurationProperties 注解。 将它 放到 Spring bean 上 之后, 它 就 会为 该 bean 中 那些 能够 根据 Spring 环境 注入 值 的 属性 赋值。

例如, 我们 可以 在 application. yml 中 按照 如下 的 方式 设置 该 属性:

taco: 
    orders: 
        pageSize: 10

使用方法:


@Controller
@RequestMapping("/orders")
@SessionAttributes("order")
public class OrderController {
    private int pageSize = 20;

  public void setPageSize(int pageSize) {
    this.pageSize = pageSize; 
  }
}

代码的 pageSize 值 默认 为 20, 但是 通过 设置 taco. orders. pageSize 属性, 我们 可以 很容易 地 将其 修改 为 任意 的 值。并且不用重启项目。

 

5. 2. 1   定义 配置 属性 的 持有 者

这里 并没有 说@ ConfigurationProperties 只能 用到 控制器 或 特定 类型 的 bean 中。

@ ConfigurationProperties 实际上 通常 会 放到 一种 特定 类型 的 bean 中, 这种 bean 的 目的 就是 持有 配置 数据。 这样 的 话, 特定 的 配置 细节 就能 从 控制器 和 其他 应用 程序 类 中 抽 离 出来, 多个 bean 也能 更容易 地 共享 一些 通用 的 配置。

配置 属性 持有 者 并没有 什么 特别 之处。 它们 只是 专门存放 Spring 环境 注入 到 其 属性 中的 bean。

5. 2. 2   声明 配置 属性 元 数据

元 数据 :IDE中 在配置文件中,鼠标悬停后可以得知相关信息

 

我觉得没什么用就不记笔记了。

 

5. 3   使用 profile 进行 配置

当 应用 部署 到 不同 的 运行时 环境 中的 时候, 有些 配置 细节 通常 会有 些 差别。配置 不同 环境 之间 有 差异 的 属性 时,

 

有种 办法 就是 使用 环境 变量, 通过 这种 方式 来 指定 配置 属性, 而 不 是在 application. properties 和 application. yml 中进 行 定义。

尽管 这种 方式 可以 运行, 但是 如果 配置 属性 比较 多, 那么 将它 们 声明 为 环境 变量 会 非常 麻烦。

 

 

相对于 这种 方式, 更推荐 采用 Spring profile。 profile 是一 种 条件 化 的 配置, 在 运行时, 根据 哪些 profile 处于 激活 状态, 可以 使用 或 忽略 不同 的 bean、 配置 类 和 配置 属性。

 

5. 3. 1   定义 特定 profile 的 属性

定义 特定 profile 相关 的 属性 的 一种 方式 就是 创建 另外 一个 YAML 或 属性 文件, 其中 只 包含 用于 生产 环境 的 属性。 文件 的 名称 要 遵守 如下 的 约定: application-{ profile 名}. yml 或 application-{ profile 名}. properties。 然后, 我们 就可以 在这里 声明 适用于 该 profile 的 配置 属性 了。

例如, 我们 可以 创建 一个 新的 名为 application- prod. yml 的 文件, 其中 包含 如下 属性:

 

spring: 
    datasource: 
        url: jdbc: mysql://localhost/tacocloud 
        username: tacouser 
        password: tacopassword 
logging: 
    level: 
        tacos: WARN

定义 特定 profile 相关 的 属性 的 另外 一种 方式 仅 适用于 YAML 配置。 它 会 将 特定 profile 的 属性 和 非profile 的 属性 都 放到 application. yml 中, 它们 之间 使用 3 个中 划线 进行 分割, 并且 使用 spring. profiles 属性 来 命名 profile。 如果 按照 这种 方式 定义 生产 环境 的 属性, 等价 的 application. yml 如下 所示:

taco:
  orders:
    pageSize: 10 
---
spring: 
    datasource: 
        url: jdbc: mysql://localhost/tacocloud 
        username: tacouser 
        password: tacopassword 
logging: 
    level: 
        tacos: WARN

我们 可以 看到, application. yml 文件 通过 一组 中 划线(---) 分成 了 两部分。 第二 部分 指定 了 spring. profiles 值,

 

通过 创建 模式 为 application-{ profile 名}. yml 或 application-{ profile 名}. properties 的 YAML 或 属性 文件, 我们 可以 按 需 定义 任意 数量 的 profile。

或者, 我们 也可 以在 application. yml 中 再输入 3 个中 划线, 结合 spring. profiles 属性 来 指定 其他 名称 的 profile, 然后 添加 该 profile 特定 的 相关 属性。

 

 

5. 3. 2   激活 profile

 

在 application. yml 中,就可以 激活 profile

spring: 
    profiles: 
        active: 
        - prod

但是, 这 可能 是 激活 profile 最 糟糕 的 一种 方式。  这个 profile 会 变成 默认 的 profile, 我们 体验 不到 使用 profile 将 生产 环境 相关 属性 和 开发 环境 相关 的 属性 分开 的 任何 好处。

 

因此, 推荐 使用 环境 变量 来 设置 处于 激活 状态 的 profile。

在 生产 环境 中, 我们 可以 这样 设置

SPRING_ PROFILES_ ACTIVE:

% export SPRING_ PROFILES_ ACTIVE= prod

这样 部署 到 该 机器 上 的 任何 应用 就都 会 激活 prod profile, 对应 的 属性 会 比 默认 profile 具备 更高 的 优先级。

 

如果 以 可执行 JAR 文件 的 形式 运行 应用, 那么 我们 还可以 以 命令行 参数 的 形式 设置 激活 的 profile:

% java -jar taco-cloud.jar --spring.profiles.active=prod

 

你 可能 已经 注意 到了, spring. profiles. active 属性 名 是 复数 形式 的 profile。 这 意味着 我们 可以 设置 多个 激活 的 profile。 如果 使用 环境 变量, 通常 这可 以 通过 逗号 分隔 的 列表 来 实现:

% export SPRING_ PROFILES_ ACTIVE = prod, audit, ha

或者

 

spring: 
    profiles: 
        active: 
        - prod
        - audit
        - ha

 

5. 3. 3   使用 profile 条件 化 地 创建 bean

 

假设 我们 希望 某些 bean 仅在 特定 profile 激活 的 情况下 才 需要 创建。 在 这种 情况下,@ Profile 注解 可以 将 某些 bean 设置 为 仅 适用于 给定 的 profile。

 

  @Bean
  @Profile("dev") 
  public CommandLineRunner dataLoader(IngredientRepository repo,
        UserRepository userRepo, PasswordEncoder encoder) {
           //……
}

如果是多个profile 环境下都要启动,则改成

@Profile({"dev","qa"}) 

如果 除了 prod 激活 时, CommandLineRunner bean 都 需要 创建,

@Profile("!prod")

我们 还可 以在 带有@ Configuration 注解 的 类 上 使用@ Profile。

 

@Profile({"!prod","!qa"})
@Configuration
public class DevelopmentConfig {
    //……
}

在这里, CommandLineRunner bean( 包括 DevelopmentConfig 中 定义 的 其他 bean) 只有 在 prod 和 qa 均 没有 激活 的 情况下 才会 创建。

 

5. 4   小结

  • Spring bean 可以 添加@ ConfigurationProperties 注解, 这样 就 能够 从 多个 属性 源 中选 取 一个 来 注入 它的 值。
  • 配置 属性 可以 通过 命令行 参数、 环境 变量、 JVM 系统 属性、 属性 文件 或 YAML 文件 等 方式 进行 设置。
  • 配置 属性 可以 用来 覆盖 自动 配置 相关 的 设置, 包括 指定 数据 源 URL 和 日志 级别。
  • Spring profile 可以 与 属性 源 协同 使用, 从而 能够 基于 激活 的 profile 条件 化 地 设置 配置 属性。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值