1. 概念定义
environmentaware 是 spring 框架中的一个 aware 回调接口。它的主要作用是让 bean 能够“感知”到 spring 容器运行时的环境配置信息(environment)。
- 所属包:org.springframework.context
- 核心方法:void setenvironment(environment environment)
2. 核心原理与执行时机
在 spring bean 的生命周期中,aware 接口的注入发生在 bean 实例化之后、初始化方法(如 @postconstruct 或 init-method)执行之前。
执行流程:
- spring 容器实例化 datasourceautoconfig。
- 容器发现该类实现了 environmentaware。
- 容器自动调用 setenvironment 方法,并将当前的 standardservletenvironment(或其它实现)作为参数传入。
- bean 获取到 environment 对象,存入成员变量供后续逻辑使用。
3. environment 对象的作用
通过 setenvironment 获取到的 environment 实例,可以访问以下三类数据:
- profiles:判断当前激活的是哪个环境(如 dev, test, prod)。
- properties:获取 application.properties/yml 中的配置。
- system settings:获取 jvm 系统属性和操作系统环境变量。
4. 代码实现示例
以下是在自动配置类中常见的用法:
import org.springframework.context.environmentaware;
import org.springframework.core.env.environment;
import org.springframework.context.annotation.configuration;
@configuration
public class datasourceautoconfig implements environmentaware {
private environment env;
@override
public void setenvironment(environment environment) {
// 保存引用,供后续使用
this.env = environment;
}
public void somemethod() {
// 1. 获取配置属性
string dburl = env.getproperty("spring.datasource.url");
// 2. 获取包含默认值的属性
integer timeout = env.getproperty("db.timeout", integer.class, 1000);
// 3. 检查当前激活的 profile
if (env.acceptsprofiles(org.springframework.core.env.profiles.of("prod"))) {
// 执行生产环境特有逻辑
}
}
}5. 为什么不直接用 @value?
虽然 @value 更简洁,但在以下场景 environmentaware 更具优势:
| 特性 | @value | environmentaware / environment |
|---|---|---|
| 灵活性 | 静态注入,写死在字段上 | 可以根据逻辑动态获取,甚至遍历属性 |
| 默认值 | 需要在占位符中指定 | 可以通过代码逻辑灵活处理缺省情况 |
| 类型安全 | 依赖 spring 转换器 | 提供 getproperty(key, targettype) 明确指定类型 |
| 复杂逻辑 | 较难实现 | 适合需要根据 activeprofiles 切换不同策略的场景 |
6. 复习要点(面试常考)
- aware 接口族:记住它和 beannameaware, applicationcontextaware 属于同一类,都是容器向 bean 注入基础设施资源。
- 解耦:它让你的配置类不需要硬编码,而是根据外部配置动态调整。
- 进阶:在 spring boot 中,如果需要更高级的属性绑定(如绑定到对象),通常配合 binder 类在 setenvironment 中使用。
在编写自定义 starter 或高级配置类时,结合 environmentaware 和 binder api 是一种非常专业的做法。它能让你像 spring boot 内部源码一样,将 environment 中的散乱配置自动封装成一个标准的 pojo(普通 java 对象)。
7. 进阶技巧:结合 binder api 实现属性批量绑定
在 spring boot 2.x 之后,引入了 binder api。它比原生的 environment.getproperty() 更强大,支持松散绑定(relaxed binding,例如 my_prop 绑定到 myprop)和对象嵌套。
7.1 代码实现
假设你有一个配置类 datasourceproperties,你想把以 spring.datasource 开头的属性全部注入进去:
import org.springframework.boot.context.properties.bind.binder;
import org.springframework.context.environmentaware;
import org.springframework.core.env.environment;
import org.springframework.context.annotation.configuration;
@configuration
public class datasourceautoconfig implements environmentaware {
private datasourceproperties properties;
@override
public void setenvironment(environment environment) {
// 1. 获取 binder 实例
binder binder = binder.get(environment);
// 2. 将指定前缀的配置绑定到具体的对象上
// 参数 1: 配置文件中的前缀
// 参数 2: 目标对象的 class
this.properties = binder.bind("spring.datasource", datasourceproperties.class)
.get(); // get() 返回绑定后的对象
system.out.println("成功绑定配置,数据库地址为: " + properties.geturl());
}
}7.2 为什么要这么做?(对比传统方案)
- 手动绑定的灵活性:虽然 @configurationproperties 也能完成绑定,但在某些场景下(例如:你的配置类需要根据 environment 中的某个值动态决定绑定哪一组前缀),binder api 提供了代码级的控制力。
- 不依赖 bean 容器:binder 可以在 bean 还没完全初始化好时,就完成属性的提取和转换。
- 处理复杂结构:binder 能够自动处理 list、map 等复杂集合的绑定,而普通的 getproperty 只能获取字符串或简单类型。
7.3 注意事项
- 异常处理:bind 方法返回的是一个 bindresult 对象。如果配置不存在,调用 .get() 会抛出异常。建议在生产代码中使用 .orelse(new datasourceproperties()) 提供默认值。
- 依赖:binder 类位于 spring-boot 包下。如果你是在纯 spring-context 环境(非 spring boot)下,则无法使用此 api。
到此这篇关于spring中environmentaware 接口的使用小结的文章就介绍到这了,更多相关spring environmentaware 接口内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论