nacos配置文件属性注入到java
前言
一、@Value注解
ps:动态配置参数配置,解耦,以下答案系gpt回答。
定义:@Value
注解是 Spring Framework 中用于注入配置值的一个注解。它通常用于将属性值注入到 Spring 管理的 Bean 中。@Value
可以从多种源获取值,包括配置文件、系统属性、环境变量等。
主要用法
-
注入配置文件中的属性值
在 Spring Boot 应用中,通常会使用
application.properties
或application.yml
文件来定义配置。可以通过@Value
注解将这些配置值注入到 Bean 中。例如:# application.properties myapp.timeout=5000
# application.yml myapp: timeout: 5000
@Component public class MyService { @Value("${myapp.timeout}") private int timeout; // 使用 timeout 属性 }
在这个示例中,
timeout
变量将被注入application.properties
或application.yml
文件中的myapp.timeout
属性值。 -
注入默认值
@Value
还允许定义默认值,当配置值不可用时,使用默认值。例如:@Component public class MyService { @Value("${myapp.timeout:3000}") // 默认值为 3000 private int timeout; // 使用 timeout 属性 }
说明
:在上面的例子中,如果 application.yml 文件中包含 myapp.exampleValue,那么 exampleValue将被设置为 Hello World。如果 application.yml 文件中没有配myapp.exampleValue,则exampleValue 会被设置为 default value,不会抛出异常。
-
注入表达式结果
@Value
注解支持 Spring Expression Language (SpEL) 表达式,可以动态计算注入值。例如:@Component public class MyService { @Value("#{T(java.lang.Math).random() * 100}") private double randomValue; // 使用 randomValue 属性 }
在这个示例中,
randomValue
会被注入一个 0 到 100 之间的随机数。 -
注入环境变量或系统属性
@Value
也可以用来注入环境变量或系统属性。例如:@Component public class MyService { @Value("#{systemProperties['user.home']}") private String userHome; // 使用 userHome 属性 }
这个示例将系统属性
user.home
注入到userHome
变量中。
注意事项
-
类型转换:Spring 会自动进行类型转换,如果注入的值与字段类型不匹配,可能会导致
类型转换异常
。确保配置值的类型与目标字段类型兼容。 -
使用场景:虽然
@Value
注解很强大,但对于复杂的配置管理,考虑使用@ConfigurationProperties
注解,它允许将配置映射到一个配置类中,并提供了更丰富的功能和更好的结构化支持。
二、@ConfigurationProperties
注解
对于更复杂的配置场景,Spring 推荐使用 @ConfigurationProperties
注解,它允许将配置属性绑定到一个 POJO 类中,从而更方便地管理和使用配置。如下所示:
1. 在 application.yml
中定义集合
假设你要在 application.yml
文件中定义一个城市列表和一个地图(字典):
myapp:
cities:
- London
- New York
- Tokyo
config:
setting1: value1
setting2: value2
2. 创建一个配置类
你需要创建一个配置类,使用 @ConfigurationProperties
注解,并在类中定义集合属性。这里我们将创建一个 MyAppProperties
类。
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Data
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "myapp") // 指定前缀
public class MyAppProperties {
private List<String> cities; // 用于存储城市列表
private Map<String, String> config; // 用于存储配置键值对
}
3. 使用注入的属性
在你的应用中,你可以通过 @Autowired
注解将上面的配置类注入到其他 Bean 中,并使用它的属性:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
private final MyAppProperties myAppProperties;
@Autowired
public MyService(MyAppProperties myAppProperties) {
this.myAppProperties = myAppProperties;
}
public void printCities() {
System.out.println("Cities: " + myAppProperties.getCities());//集合
}
public void printConfig() {
System.out.println("Config: " + myAppProperties.getConfig());//map
}
}
4. 启用配置属性功能
在 Spring Boot
应用的主类上,确保包含 @EnableConfigurationProperties
注解,这通常是默认启用的,但在某些情况下需要明确添加。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
5. 运行应用
当你运行这个 Spring Boot 应用时,MyService
中的 printCities
和 printConfig
方法将打印从 application.yml
中注入的城市列表和配置字典。
总结
通过上述方式,你可以方便地在 Spring Boot 应用中通过注解将 YAML 文件中的集合属性注入到 Java 类中。这种方法使得配置更加整洁且容易管理。
三 、扩展
1**Spring Boot 启动过程
SpringApplication 初始化**:启动时,`SpringApplication` 类创建并配置上下文。
2. **加载 `application.properties` 或 `application.yml`**:配置文件中的属性被加载到环境中。
3. **创建 `ApplicationContext`**:通过 `SpringApplication.run()` 创建 `ApplicationContext`。
4. **创建和配置 Bean**:在 `ApplicationContext` 创建过程中,Spring 扫描、实例化并配置 Beans。
5. **属性注入**:
- **`@Value` 注解**:首先处理通过 `@Value` 注解的属性注入。
- **`@ConfigurationProperties` 注解**:随后注入 `@ConfigurationProperties` 注解的类中的属性。
6. **执行 BeanPostProcessors**:在 Bean 初始化之前,执行 `BeanPostProcessor` 的 `postProcessBeforeInitialization` 方法。
7. **初始化 Bean**:执行 Bean 的初始化方法(例如 `@PostConstruct`)。
8. **执行 BeanPostProcessors**:在 Bean 初始化之后,执行 `BeanPostProcessor` 的 `postProcessAfterInitialization` 方法。
9. **完成上下文刷新**:上下文完全准备好后,应用启动完成。
此过程确保在应用启动时,所有的配置和属性都会被正确地加载和注入到相应的 Beans 中。
`@RefreshScope` 是 Spring Cloud 提供的一个注解,主要用于支持动态刷新配置。当使用 Spring Cloud Config 进行外部配置管理时,添加此注解的 Bean 可以在运行时通过 `/actuator/refresh` 端点获取最新的配置信息。
2**@RefreshScope**
使用场景
- 当你需要从外部配置源(如 Git、SVN 或其他配置存储)动态更新配置而无需重启整个应用时,
@RefreshScope
是非常有用的。 - 适用于配置中心管理的应用,尤其是在微服务架构中,当需要更新配置信息而不想停掉服务时。
示例
-
添加依赖
在
pom.xml
中添加 Spring Cloud 相关依赖:<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
-
定义配置类
创建一个配置类,并在需要动态刷新的地方使用
@RefreshScope
注解:import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Component; @Component @RefreshScope public class MyConfig { @Value("${myapp.exampleValue:default value}") private String exampleValue; public String getExampleValue() { return exampleValue; } }
-
创建 REST 控制器
创建一个控制器,在应用中调用配置值:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @Autowired private MyConfig myConfig; @GetMapping("/value") public String getValue() { return myConfig.getExampleValue(); } }
-
刷新配置
启动应用后,通过访问
/actuator/refresh
端点即可刷新配置,这需要在application.yml
中启用 actuator:management: endpoints: web: exposure: include: refresh
刷新流程
-
当配置更改时,修改外部配置源并调用
/actuator/refresh
端点,Spring 会重新加载与@RefreshScope
注解的 Bean 相关的配置信息。 -
此时,下次访问
MyController
中的/value
端点时,会返回最新的配置信息,而不需要重启应用。
小结
@RefreshScope
提供了一种优雅的方式来动态管理和刷新配置,显著提高了微服务架构中的灵活性和可维护性。通过它,可以确保应用在运行时能够持续迭代和适应变化的配置需求。