欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot 加载配置多种方式

程序员文章站 2022-07-12 13:53:00
...

在开发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小节。这里简要说明一下:

  1. 热加载,也就是根目录下的开发工具全局设置属性(当开发工具**时为~/.spring-boot-devtools.properties)。
  2. 测试配置,具体指@TestPropertySource注解和@SpringBootTest#properties注解属性值。
  3. 命令行参数。
  4. Servlet 参数ServletConfigServletContext
  5. java:comp/envJNDI属性。
  6. 先系统属性System.getProperties(),再操作系统环境变量。
  7. application-{profile}.properties(先jar外后jar内)。
  8. application.properties(先jar外后jar内)。
  9. @PropertySource引入的配置源。
  10. 通过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);
    }

}

这段代码展示了我们获取单个属性值的各种姿势,接下来我们逐个解刨。

  1. @Value("${properties.id}"),将@Value()注解的value属性的值作为我们配置文件中的键值,获取我们加载好的配置文件中的值。
  2. @Value("${properties.name:jerome}"),细心的同学会发现我们并没有properties.name的配置,这是我们给这个配置指定了一个默认值。当我们的properties.name不存在的时候,取到的值是jerome
  3. age这个字段值的获取没有使用注解的方式,而是是用了编码的方式通过Environment对象来获取加载好的配置的值。其实这里也可以使用@Autowired的方式获取Environment对象。
  4. student字段就是获取一个布尔值。
  5. birth字段就是获取一个日期类型的值。
  6. array获取一个数组。
  7. 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
    }
}

这段代码展示了我们同时获取多个属性值的各种姿势,接下来我们逐个解刨。

  1. 通过student.name配置获取到name字段的值。
  2. 通过配置student.array[0]来获取定义好的String[]数组的值。
  3. 通过配置student.map.key1 = value1获取定义的Map<String,Object>的值。
  4. 通过student.course来获取指定的对象。这里需要注意一下,如果这个对象是内部类需要在定义的时候对其进行初始化,否则会获取失败一直返回null,外部类就不用注意这点。
  5. 这里student.course.mark通过${random}来获取一个100以内的随机数。

在这个Student类中使用了两个注解,接下来分别解释一下它们的作用:

  • 官方提供@ConfigurationProperties注解就是为了方便我们将配置信息绑定到Bean上,这个注解的valueprefix属性都互相标注了@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 加载配置多种方式

相关标签: 配置