Spring Boot 加载配置多种方式
在开发Spring Boot
应用的时候,也会遇到使用外部配置资源,这些配置资源能够与代码相互配合,避免硬编码 方式,提供应用数据或行为变化的灵活性。也就是说我们需要灵活的用好配置文件,接下来就来介绍获取配置文件的内容的各种姿势。
演示环境
- IntelliJ IDEA 2018.2.1 (Community Edition)
- Spring Boot 2.1.1.RELEASE
- Maven 3.3.9
外部配置资源介绍
1、常见的外部配置资源
在开发的过程中,也许会用到不同的配置资源,这里简单的列一下常见的:
- Properties 文件
- YAML 文件
- XML 文件
- 环境变量
- Java 系统属性
- 命令行参数配置
2、资源的加载顺序
Spring Boot
规定了这些外部配置资源的加载的优先级,详情参考官方文档Externalized Configuration小节。这里简要说明一下:
- 热加载,也就是根目录下的开发工具全局设置属性(当开发工具**时为
~/.spring-boot-devtools.properties
)。 - 测试配置,具体指
@TestPropertySource
注解和@SpringBootTest#properties
注解属性值。 - 命令行参数。
- Servlet 参数
ServletConfig
和ServletContext
。 -
java:comp/env
的JNDI
属性。 - 先系统属性
System.getProperties()
,再操作系统环境变量。 -
application-{profile}.properties
(先jar
外后jar
内)。 -
application.properties
(先jar
外后jar
内)。 -
@PropertySource
引入的配置源。 - 通过
SpringApplication.setDefaultProperties
方法设置的属性。
这里的加载的优先级,高优先级属性源里设置的属性都会覆盖低优先级的相同属性的值。
读取配置
首先准备一个Spring Boot
项目,这个就不多说了,接下来就开始演示加载配置的不同方式。
1、从application.properties
中加载单个配置
首先我们先编写application.properties
配置文件的部分配置:
properties.id = 1
properties.age = 18
properties.student = true
properties.birth = 2018/12/11
properties.array = a,b,c
properties.list = one,two,three
接下来我们编写一个Controller
,使用@Value
注解和Environment
方式来加载我们获取的配置文件的值,并配置一个/properties
路径验证其正确性。详见PropertiesController
代码:
/**
* 加载properties文件中的属性的 {@link RestController}
*
* @author Jerome Zhu
*/
@RestController
public class PropertiesController implements EnvironmentAware{
@Value("${properties.id}")
private Integer id;
@Value("${properties.name:jerome}")
private String name;
private Integer age;
@Value("${properties.student}")
private Boolean student;
@Value("${properties.birth}")
private Date birth;
@Value("${properties.array}")
private String[] array;
@Value("${properties.list}")
private List<String> list;
@GetMapping("/properties")
public Map<String, Object> getProperties() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("id", id);
result.put("name", name);
result.put("age", age);
result.put("student", student);
result.put("birth", birth);
result.put("array", array);
result.put("list", list);
return result;
}
@Override
public void setEnvironment(Environment environment) {
this.age = environment.getProperty("properties.age", Integer.class);
}
}
这段代码展示了我们获取单个属性值的各种姿势,接下来我们逐个解刨。
-
@Value("${properties.id}")
,将@Value()
注解的value
属性的值作为我们配置文件中的键值,获取我们加载好的配置文件中的值。 -
@Value("${properties.name:jerome}")
,细心的同学会发现我们并没有properties.name
的配置,这是我们给这个配置指定了一个默认值。当我们的properties.name
不存在的时候,取到的值是jerome
。 -
age
这个字段值的获取没有使用注解的方式,而是是用了编码的方式通过Environment
对象来获取加载好的配置的值。其实这里也可以使用@Autowired
的方式获取Environment
对象。 -
student
字段就是获取一个布尔值。 -
birth
字段就是获取一个日期类型的值。 -
array
获取一个数组。 -
list
通过配置获取一个集合
通过我的不断尝试,没有找的通过
@Value
注入Map
的方式。
让后我们启动项目通过访问localhost:8080/properties
,会得到如下的JSON
串:
{"id":1,"name":"jerome","age":18,"student":true,"birth":"2018-12-10T16:00:00.000+0000","array":["a","b","c"],"list":["one","two","three"]}
说明我们获取配置成功了。
2、从application.properties
中同时加载多个配置
首先我们还是先编写application.properties
配置文件的部分配置:
student.name = JeromeZhu
student.array[0] = a
student.array[1] = b
student.map.key1 = value1
student.map.key2 = value2
student.course.name = English
student.course.mark = ${random.int(100)}
这个配置文件中需要说明一点,这${random.int(100)}
到底是个什么东东。这是Spring Boot
给我们提供的在配置文件中使用${random}
可以用来生成各种不同类型的随机值,例如:生成 int 值、long 值或者 string 字符串。具体的实现请参考org.springframework.boot.env.RandomValuePropertySource
这个类。
接下来写来编写配置文件的承载实体Student
类:
/**
* 学生类
*
* @author Jerome Zhu
*/
@ConfigurationProperties("student")
@Component
public class Student {
private String name;
private String[] array;
private Map<String, Object> map;
private Course course = new Course();
// 省略 getter 和 setter
public class Course{
private String name;
private Integer mark;
// 省略 getter 和 setter
}
}
这段代码展示了我们同时获取多个属性值的各种姿势,接下来我们逐个解刨。
- 通过
student.name
配置获取到name
字段的值。 - 通过配置
student.array[0]
来获取定义好的String[]
数组的值。 - 通过配置
student.map.key1 = value1
获取定义的Map<String,Object>
的值。 - 通过
student.course
来获取指定的对象。这里需要注意一下,如果这个对象是内部类需要在定义的时候对其进行初始化,否则会获取失败一直返回null
,外部类就不用注意这点。 - 这里
student.course.mark
通过${random}
来获取一个100以内的随机数。
在这个Student
类中使用了两个注解,接下来分别解释一下它们的作用:
- 官方提供
@ConfigurationProperties
注解就是为了方便我们将配置信息绑定到Bean
上,这个注解的value
和prefix
属性都互相标注了@AliasFor()
注解,所以这里使用@ConfigurationProperties(prefix = "student")
也能达到同样的效果。这里的@ConfigurationProperties
还可以配合@PropertySource
加载指定路径下的配置文件,也可以配合@Validated
使用对加载的值做数据校验。 - 在这里使用
@Component
这个注解是为了把这个类标注为组件加载到Spring
容器中,方便我们后续使用@Autowired
注入Student
对象。
编写Controller
来验证我们获取属性是否成功:
/**
* {@link Student} 的{@link RestController}
*
* @author Jerome Zhu
*/
@RestController
public class StudentController {
@Autowired
private Student student;
@GetMapping("/student")
public Student getStudent() {
return student;
}
}
让后我们启动项目通过访问localhost:8080/properties
,会得到如下的JSON
串:
{"name":"JeromeZhu","array":["a","b"],"map":{"key1":"value1","key2":"value2"},"course":{"name":"English","mark":5}}
发现正是我们配置的内容,说明我们获取配置成功了。
3、@Value
和@ConfigurationProperties
的比较
@ConfigurationProperties | @Value | |
---|---|---|
注入方式 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
所以这里,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,建议使用@Value;如果我们专门编写了一个javaBean
来和配置文件进行映射,我们就直接使用@ConfigurationProperties
,同时可以搭配@PropertySource
加载指定路径下的配置文件。
4、从xml配置文件中加载配置
我们在Spring Boot
还没有出现的时候,使用Spring
开发项目大多数都是使用xml
的方式来配置项目。在这里Spring Boot
为了兼容之前的项目,也提支持导入xml
配置文件。
首先编写application.properties
配置文件的部分配置:
xml.bean.id = 2
xml.bean.desc = ${student.name} is a student.
这里xml.bean.desc
引用了student.name
的值,当配置文件加载的时候${student.name}
占位符会被替换成student.name
的值。
接下来写来编写配置文件的承载实体XmlBean
类:
/**
* Xml 配置文件对应的实体
*
* @author Jerome Zhu
*/
public class XmlBean {
private Integer id;
private String name;
private String desc;
// 省略getter和setter
}
再接着我们在resources
目录下创建一个spring
文件夹,在该文件夹下开始编写我们的context.xml
配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="xmlBean" class="xin.jerome.configuration.entity.XmlBean">
<property name="id" value="${xml.bean.id}"/>
<property name="name" value="Jerome"/>
<property name="desc" value="${xml.bean.desc}"/>
</bean>
</beans>
在这个文件中,我们使用了${}
占位符来读取我们核心配置文件application.properties
中的内容。Spring Boot
读取完配置文件,向容器值注入一个xmlBean
。其实这里的配置文件相当于一个被@Configuration
标注的类,<bean></bean>
标签相当于一个被@Bean
标注的一个方法。只是走到这一步还不够,我们还需要告诉Spring Boot
我们需要添加配置文件。
/**
* 启动类
* SpringBoot 配置相关的Demo
*
* @author Jerome Zhu
*/
@SpringBootApplication
@ImportResource(locations = {"classpath:spring/context.xml"})
public class ConfigurationApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigurationApplication.class, args);
}
}
这里使用@ImportResource
注解来通知Spring Boot
需要加载我们xml
配置资源。
编辑XmlBeanController
来验证加载配置是否成功:
/**
* 验证加载xml配置是否成功的{@link RestController}
*
* @author Jerome Zhu
*/
@RestController
public class XmlBeanController {
@Autowired
private XmlBean xmlBean;
@GetMapping("/xmlbean")
public XmlBean getXmlBean() {
return xmlBean;
}
}
让后我们启动项目通过访问localhost:8080/xmlbean
,会得到如下的JSON
串:
{"id":2,"name":"Jerome","desc":"JeromeZhu is a student."}
看到正是我们想看到的内容,说明我们获取配置成功了。
总结
通过上面的分析,我们大致了解配置资源大概都有哪些。并且Spring Boot
加载配置资源的方式,通过@Value
注解来注入单个的配置属性,通过@ConfigurationProperties
注解来注入多个以及复杂的javaBean
。还了解了通过${random}
在配置文件中获取随机值。
具体的代码可以参考GitHub:spring-boot-demo-configuration小节。
原文链接:Spring Boot 加载配置多种方式
上一篇: mysql window免安装版配置流程
下一篇: mysql my.ini 配置文件
推荐阅读
-
spring boot application properties配置实例代码详解
-
详解spring boot starter redis配置文件
-
基于vue中css预加载使用sass的配置方式详解
-
spring boot启动时加载外部配置文件的方法
-
spring boot 注入 property的三种方式(推荐)
-
Spring boot工具类静态属性注入及多环境配置详解
-
干货分享:ASP.NET CORE(C#)与Spring Boot MVC(JAVA)异曲同工的编程方式总结
-
Spring Boot 配置元数据指南
-
spring boot加载资源路径配置和classpath问题解决
-
深入理解spring boot异步调用方式@Async