【SpringBoot】第2章 SpringBoot核心配置与注解

学习目标

  • 熟悉SpringBoot全局配置文件的使用

  • 熟悉SpringBoot自定义配置

  • 掌握SpringBoot配置文件属性值注入

  • 掌握Profile多环境配置

  • 了解随机值设置以及参数间引用

2.1 全局配置文件

全局配置文件能够对一些默认配置进行修改。SpringBoot使用一个application.properties或者application.yaml的文件作为全局配置文件,该文件存放在src/main/resource目录或者类路径的/config,一般会选择resource目录。本节将针对这两种全局配置文件进行讲解。

2.1.1 application.properties配置文件

使用Spring Initializr方式构建SpringBoot项目时,会在resource目录下自动生成一个空的application.properties文件,SpringBoot下古墓启动时会自动加载application.properties文件。

我们可以在application.properties文件中定义SpringBoot项目的相关属性,当然,这些相关属性可以时系统属性,环境便利,命令参数等信息,也可以是自定义配置文件名称和位置。

接下来我们通过一个案例对SpringBoot项目中application.properties配置文件的具体使用进行讲解。

(1)使用Spring Initializr方式创建一个SpringBoot项目,定义号包名,选择Web依赖。

(2)为了方便查看application.properties配置文件属性配置的效果,我们在包下创建domain包,并在该包下创建两个实体类Pet和Person。

Pet.java

java 复制代码
package com.yhh.domain;

/**
 * 宠物实体类
 */
public class Pet {
    private String type;
    private String name;

    public Pet() {
    }

    public Pet(String type, String name) {
        this.type = type;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Pet{" +
                "type='" + type + '\'' +
                ", name='" + name + '\'' +
                '}';
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Person.java

java 复制代码
package com.yhh.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 人类实体类
 */
//用于将Person类作为Bean注入Spring容器
@Component
//将配置文件中以person开头的属性注入该类中
@ConfigurationProperties(prefix = "person")
public class Person {
    private int id;
    private String name;
    private List hobby;//爱好
    private String[] family;//家庭成员
    private Map map;
    private Pet pet;//宠物

    public Person() {
    }

    public Person(int id, String name, List hobby, String[] family, Map map, Pet pet) {
        this.id = id;
        this.name = name;
        this.hobby = hobby;
        this.family = family;
        this.map = map;
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", hobby=" + hobby +
                ", family=" + Arrays.toString(family) +
                ", map=" + map +
                ", pet=" + pet +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List getHobby() {
        return hobby;
    }

    public void setHobby(List hobby) {
        this.hobby = hobby;
    }

    public String[] getFamily() {
        return family;
    }

    public void setFamily(String[] family) {
        this.family = family;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }
}

准备了两个实体类文件,后续我们会演示将application.properties配置文件中的自定义配置属性注入Person实体类的对应属性中。其中,@ConfigurationProperties(prefix = "person")注解的作用是将配置文件中以person开头的属性值通过seter方法注入实体类对应属性中,@Component注解的作用是将当前注入属性值的Person类对象作为Bean组件放到Spring容器中,只有这样它才能被@ConfigurationProperties注解赋值。

在上述自定义Person类中,添加了一个@Component注解,将该自定义类作为Spring容器的组件,其根本目的是让SpringBoot可以自动扫描到该组件,然后进行其他功能实现。而如果想要将一个自定义类添加为Spring容器的组件,除了可以使用@Component注解外,还可以使用@Controller,@Service,@Repository,@Configuration等注解,分别用于控制层类,业务逻辑层类,数据访问层类以及全局配置类等。

(3)打开项目的resources目录下的application.properties配置文件,在该配置文件中编写需要对Person类设置的配置属性

java 复制代码
# 对实体类对象Person进行属性配置
person.id=1
person.name=tom
person.hobby=play,read,sleep
person.family=father,mother
person.map.k1=v1
person.map.k2=v2
person.pet.type=dog
person.pet.name=kitty

在SpringBoot默认全局配置文件application.properties中通过"person.xx"对Person的相关属性进行了配置,这些配置属性会通过@ConfigurationProperties(prefix="person")注解注入Person实体类的对应属性中。

在编写application.properties配置文件时,由于要配置的Person对象属性时我们自定义的,SpringBoot无法自动识别,所以不会有任何书写提示。在实际开发中,为了出现代码提示的效果来方便配置,在使用@ConfigurationProperties注解进行配置文件属性值注入时,可以在pom.xml文件中添加一个SpringBoot提供的配置处理器依赖

XML 复制代码
<!--配置处理器依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

在pom.xml中添加上述配置依赖后,还需要重新运行项目启动类或者使用"Ctrl+F9"组合键(即BuildProject)重构当前项目方可生效。

为了查看application.properties配置文件是否正确,同时查看属性配置效果,在项目的测试类中引入Person实体类对象,并进行输出测试。

java 复制代码
package com.yhh;

import com.yhh.controller.MyController;
import com.yhh.domain.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 使用SpringInitializr方式自动创建的主程序启动类对应的单元测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {


    @Autowired
    Person person;

    @Test
    public void printPerson(){
        System.out.println(person);
    }
    @Test
    public void contextLoads() {
    }


}

可在控制台观察到数据的显示和打印输出。

2.1.2 application.yaml配置文件

YAML文件格式是SpringBoot支持的一种JSON超集文件格式,相较于传荣的Properties配置文件,YAML文件以数据为核心,是一种更为直观且容易被计算机识别的数据序列化格式。application.yaml配置文件的工作原理和application.properties是一样的,只不过YAML格式配置文件看起来更简洁一些。

application.yaml文件使用"key:(空格)value"格式配置属性,使用缩进控制层级关系。

这里我们针对不同数据类型的属性值,介绍以下YAML文件配置属性的写法:

(1)value值为普通数据类型(如数字,字符串,布尔等)

当YAML配置文件中配置的属性值为普通数据类型时,可以直接配置对应的属性值,同时对于字符串类型的属性值,不需要额外添加引号

java 复制代码
server:
	port:8081
	path:/hello

(2)value值为数组和单列集合

当YAML配置文件中配置的属性值为数组或单列结合类型时,主要有两种书写方式:缩进式写法和行内式写法。

其中缩进式写法还有两种表示形式

java 复制代码
person:
	hobby:
		- play
		- read
		- sleep

或者是如下形式:

java 复制代码
person:
	hobby:
		play,
		read,
		sleep

上述代码使用两种缩进式写法为person对象的属性hobby赋值,其中一种是通过"-(空格)属性值"的形式为属性赋值,另外一种是直接赋值并使用英文逗号分隔属性值。

在YAML配置文件中,还可以将上述缩进式写法简化为行内式写法

java 复制代码
person:
	hobby:[play,read,sleep]

在yaml配置文件中,行内式的写法显然比缩进是更加简便。使用行内式写法设置属性值时,中括号"[]"时可以省略的,程序会自动匹配校对属性的值。

(3)value值为Map集合和对象

当YAML配置文件中配置的属性值为Map集合或对象类型时,YAML配置文件格式同样可以分为两种书写方式:缩进式写法和行内式写法。

缩进式写法

java 复制代码
person:
	map:
		k1:v1
		k2:v2

行内式写法

java 复制代码
person:
	map:{k1:v1,k2:v2}

在YAML配置文件中,配置的属性值为Map集合或对象类型时,缩进式写法的形式按照YAML文件格式编写即可,而行内式写法的属性值要用大括号"{}"包含。

接下来我们演示使用yaml文件为Person对象赋值

在该项目的resources目录下创建application.yaml配置文件,在该配置文件中设置Person对象的属性值

java 复制代码
# 对实体类对象Person进行属性配置
person:
  id: 2
  name: 张三
  hobby: [sing,read,sleep]
  family: [father,mother]
  map: {k1: v3,k2: v4}
  pet: {type: cat,name: tom}

这些配置的属性将会通过@ConfigurationProperties(prefix = "person")注解注入Person实体类的对应属性中。

接下来再次通过单元测试类进行测试访问,我们会发现输出打印的结果还是properties中赋值的属性值,这是因为在SpringBoot项目中properties文件优先级高于yaml文件。因此我们将properties文件中的属性值进行注释,再次测试即可。

通过两种方式的对比,我们发现yaml文件的方式更简洁,因此我们后期都使用yaml文件的方式进行配置赋值。

2.2 配置文件属性值的注入

2.2.1 使用@ConfigurationProperties注入属性

SpringBoot提供的@ConfigurationProperties注解用来快速,方便的将配置文件中的自定义属性值批量注入某个Bean对象的多个对应属性中。假设现在有一个配置文件,使@ConfigurationProperties注入配置文件的属性

需要注意的是,使用@ConfigurationProperties注解批量注入属性值时,要保证配置文件中的属性与对应实体类的属性名一致,否则无法正确获取并注入属性值。

2.2.2 使用@Value注入属性

@Value注解时Spring框架提供的,用来读取配置文件中的属性值并逐个注入Bean对象的对应属性中。SpringBoot框架对Spring框架中的@Value注解进行了默认继承,所以在SpringBoot框架中还可以使用该注解读取和注入配置文件属性值。例如:

在domain包中创建一个Student.java

java 复制代码
package com.yhh.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Student {
    @Value("10")
    private int id;//学号
    @Value("${person.name}")
    private String name;
    private String phone;
    private String sex;
    private String address;
    private int age;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone='" + phone + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", age=" + age +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student(String phone, String sex, String address, int age) {
        this.phone = phone;
        this.sex = sex;
        this.address = address;
        this.age = age;
    }

    public Student() {
    }
}

在单元测试类中测试一下:

java 复制代码
package com.yhh;

import com.yhh.controller.MyController;
import com.yhh.domain.Person;
import com.yhh.domain.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 使用SpringInitializr方式自动创建的主程序启动类对应的单元测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {


    @Autowired
    Student student;
    @Test
    public void printStudent(){
        System.out.println(student);
    }


}

测试结果如下

2.2.3 两种注解对比分析

下面我们针对以上两种属性值注入的方式进行对比

对比点 @ConfigurationProperties @Value
底层框架 SpringBoot Spring
功能 批量注入配置文件中的属性 单个注入
setter方法 需要 不需要
复杂类型属性注入 支持 不支持
松散绑定 支持 不支持
JSR303数据校验 支持 不支持
SpEL表达式 不支持 支持

具体说明如下:

  1. 底层框架

    @ConfigurationProperties注解时SpringBoot框架自带的,而@Value注解时Spring框架支持的,只不过SpringBoot框架对Spring进行了默认支持,所以也可以使用@Value注解的相关功能

  2. 功能

    @ConfigurationProperties能够将配置文件中的属性批量注入Bean对象,而@Value只能一个一个单独注入

  3. 属性setter方法

    在使用@ConfigurationProperties注解进行配置文件属性值读取注入时,还必须为每一个属性设置setter方法,通过对应的注解才能够将配置文件中的属性一一匹配并注入对应的Bean属性上。如果配置文件中没有配置属性值,则会自动将对应的Bean属性设置为空。

  4. 复杂类型属性注入

    @ConfigurationProperties和@Value都能注入配置文件中的属性,不同的是,@ConfigurationProperties支持任意数据类型的属性注入,包括基本数据类型和复杂数据类型,而@Value只能注入基本类型的属性。

  5. 松散绑定

    @ConfigurationProperties注解进行配置文件属性值注入时,支持松散绑定语法

java 复制代码
person.firstName=james
person.first-name=james
person.first_name=james
PERSON.FIRST_NAME=james

如果要注入上述松散绑定语法的属性,那么使用@Value注入是无效的,只能使用@ConfigurationProperties

  1. JSR303数据校验

@ConfigurationProperties注解进行配置文件属性值注入时,支持JSR303数据校验,其主要作用时校验配置文件中注入对用Bean属性的值时否符合相关值的规则

java 复制代码
package com.yhh.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.Email;

@Component
@ConfigurationProperties(prefix = "person")
@Validated //引入Spring框架支持的数据校验规则
public class Example {
    @Email //对属性进行规则匹配
    private String  email;
    public void setEmail (String email){
        this.email=email;
    }
}

上述代码中,使用@ConfigurationProperties注解注入配置文件属性值时,在实体类Example上引入了@Validated注解进行数据校验,在属性email上引入@Email注解进行邮件规则校验。如果注入的配置文件属性值不符合相关校验规则,程序会自动报错。@Value注解不支持JSR303数据校验。

7.SpEL表达式

@Value注解注入配置文件属性时,支持SpE来表达是语法,即"#{xx}"

java 复制代码
@Value("#{5*2}") //使用@Value注解的SpEL表达式直接为属性注入值
private int id;

以上代码在不适用配置文件的情况下,只有@Value注解可以使用。

对于以上两种方式的分析,在实际开发中该如何选择?需要对单个属性进行赋值时使用@Value,需要对大量的属性赋值时使用@ConfigurationProperties注解。

2.3 SpringBoot自定义配置

SpringBoot免除了项目中大部分的手动配置,对于一些特定情况,我们可以通过修改全局配置文件以适应具体产生环境,可以说,几乎所有的配置都可以写在全局配置文件中,SpringBoot会自动加载全局配置文件从而免除我们手动加载的烦恼。但是,如果我们自定义配置文件SpringBoot时无法识别这些配置文件的,此时就需要我们手动加载。

2.3.1 使用@PropertySource加载配置文件

如果要加载自定义配置文件,可以使用@PropertySource和@Configuration注解实现。@PropertySource注解可以指定自定义配置文件的位置和名称,@Configuration注解可以将实体类指定为自定义配置类。如果需要将自定义配置文件中的属性值注入实体类属性,可以使用@ConfigurationProperties或@Value注入属性值。

接下来我们来演示一下该注解的使用,我们在resouces目录下创建一个test.properties自定义配置文件

java 复制代码
# 对实体类对象MyProperties进行属性配置
test.id=110
test.name=test

在domain包下创建MyProperties类

java 复制代码
package com.yhh.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration //自定义配置类
@PropertySource("classpath:test.properties")//指定自定义配置文件位置和名称
@EnableConfigurationProperties(MyProperties.class)//开启对应配置类的属性注入功能
@ConfigurationProperties(prefix = "test")//指定配置文件注入属性前缀
public class MyProperties {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "MyProperties{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Configuration注解用于表示当前类时一个自定义配置类,该类会作为Bean组件添加到Spring容器中,这里等同于@Conponent注解。

@PropertySource("classpath:test.properties")注解指定了自定义配置文件的位置和名称,此代码表示自定义配置文件为classpath类路径下的test.properties文件。

@ConfigurationProperties(prefix = "test")注解将上述自定义配置文件test.properties中的test开头的属性值注入该配置类属性中。

@EnableConfigurationProperties(MyProperties.class)注解表示开启对应配置类MyProperties的属性注入功能,该注解时配合@ConfigurationProperties使用的。如果自定义配置类使用了@Component注解而非@Configuration注解,那么@EnableConfigurationProperties注解可以省略

接着我们可以在单元测试类中进行测试

java 复制代码
package com.yhh;

import com.yhh.controller.MyController;
import com.yhh.domain.MyProperties;
import com.yhh.domain.Person;
import com.yhh.domain.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 使用SpringInitializr方式自动创建的主程序启动类对应的单元测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    MyProperties myProperties;

    @Test
    public void printProperties(){
        System.out.println(myProperties);
    }


}
2.3.2 使用@ImportResource加载XML配置文件

传统的Spring项目配置主要基于XML文件。SpringBoot框架在Spring4.x基础上进行了改进,默认不再使用XML文件配置项目,且XML配置文件不会加载到Spring容器中。如果希望将外部的XML文件加载到程序中,可以使用@ImportResource注解加载配置文件。

@ImportResource注解标注在一个配置类上,通常放置在应用启动类上,使用时需要指定XML配置文件的路径和名称。

接下来我们演示代码,我们创建一个config包,并在该包下创建一个类MyService,该类中不需要编写任何代码

java 复制代码
package com.yhh.config;

public class MyService {
}

在resources目录下创建一个beans.xml的XML自定义配置文件,在该配置文件中将MyService配置为Bean

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 id="myService" class="com.yhh.config.MyService"></bean>
</beans>

编写玩Spring的XML配置文件后。SpringBoot默认时无法识别的,为了保证XML配置文件生效,需要在项目启动类上添加@ImportResource注解来指定XML文件位置

接下来我们在单元测试类中进行测试MyService类是否能被注入Spring容器中

通过显示,可以看到该类已被注入成功。

2.3.3 使用@Configuration编写自定义配置类

上一节讲解了如何在SpringBoot中引入自定义的XML配置文件,这种配置方式在实际开发中的特殊情况下才会使用。在SpringBoot开发中,"约定大于配置"的思想,更推荐使用配置类的方式代替XML配置。

使用@Configuration注解可以指定配置类,它的作用和XML配置是一样的,配置类中@Bean注解方法返回的对象都将作为Bean注入Spring容器,并且默认情况下,使用@Bean注解的方法名就是组件名。

下面我们来演示以下使用@Configuration编写自定义配置类的用法

在包下创建config包,新建一个类MyConfig,并使用@Configuration注解将该类声明一个配置类

java 复制代码
package com.yhh.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {
    //将返回值对象作为组件添加到Spring容器中,该组件id默认为方法名
    @Bean
    public MyService myService(){
        return new MyService();
    }
}

MyConfig是@Configuration注解声明的配置类(类似于声明了一个XML配置文件),该配置类会被SpringBoot自动扫描识别;使用@Bean注解的myService()方法,其返回值对象会作为组件添加到Spring容器中(类似于XML配置文件中的<Bean>变迁配置),并且该组件的id默认是方法名myService。

接下来我们通过测试类来测试,测试之前需要将@ImportResource注解注释,配置类的方式是不需要该注解进行加载的。

2.4 Profile多环境配置

在实际开发中,应用程序通过需要部署到不同的运行环境中,如开发环境,测试环境,生产环境等。不同的环境可能需要不同的环境配置,针对这种情况,显然手动修改配置文件适应不同开发环境的做法是不太现实的,此时通常会对项目进行多环境配置。SpringBoot框架提供了两种多环境配置的方式,分别是Profile文件多环境配置和@Profile注解多环境配置。

2.4.1 使用Profile文件进行多环境配置

在SpringBoot框架中,使用Profile配置文件进行多环境配置时,该配置文件名必须满足application-{profile}.properties的格式,其中{profile}对应具体的环境表示。这里以开发环境,测试环境和生产环境为例,编写对应环境的配置文件

java 复制代码
application-dev.properties  //开发环境配置文件
application-test.properties  //测试环境配置文件
application-prod.properties  //生产环境配置文件

如果想要使用上述对应环境的配置文件,只需要在SpringBoot全局配置文件中激活指定环境的配置文件即可。例如,在控制台执行下列命令激活环境配置

java 复制代码
java -jar xxx.jar --spring.profiles.active=dev

除了在控制台使用命令激活指定环境的方式外,还可以在项目全局配置文件中配置spring.profiles.active属性激活配置。这里以激活dev开发环境配置文件为例,在全局配置文件application.properties中配置激活环境的属性

java 复制代码
#激活开发环境配置文件
spring.profiles.active=dev

接下来我们演示代码,在resource目录下,按照Profile文件命名规则创建不同运行环境对应的配置文件,这里分别创建application-dev.properties,application-test.properties和application-prod.properties多环境配置文件,并在各个配置文件中对服务端口进行不同的设置

java 复制代码
# 配置开发环境下端口号
server.port=8081
java 复制代码
# 配置测试环境下端口号
server.port=8082
java 复制代码
# 配置生产环境下端口号
server.port=8083

在SpringBoot项目中,程序内部默认端口为8080,而上述代码中通过Profile文件进行了多环境配置,不同的运行环境设置了不同的服务端口号。

打开resouces目录下的全局配置文件application.properties,在该配置文件中配置spring.profiles.active属性选择性激活Profile文件设置

java 复制代码
# 指定要激活的profile多环境配置文件
spring.profiles.active=dev

为了查看使用Profile文件进行多环境配置的效果,直接启动项目的启动类,并查看控制台输出效果。

从上图可以看出,程序正常启动,并显示服务启动的端口号为8081,这与选择激活的配置文件application-dev.properties中的端口号一直,说明Profile多环境配置文件生效。如果想使用Profile文件激活其他环境,可以在全局配置文件application.properties中设置对应的配置文件,重启项目查看效果。

2.4.2 使用@Profile注解进行多环境配置

除了使用Profile注解继续宁多环境配置外,还可以使用@Profile注解进行多环境配置。@Profile注解主要作用于类,并通过value属性指定配置环境(等同于Profile文件名称中的profile值)。使用@Profile注解配置的环境,同样需要在全局配置文件中激活。

接下来我们通过项目进行演示,在config包下创建一个用于配置数据库的接口文件DBConnector

java 复制代码
package com.yhh.config;

public interface DBConnector {
     void configure();
}

接着在config包下创建三个实现了DBController接口的类DevController,TestController和ProdController并重写了configure()方法,分别模拟链接配置不同的数据库环境

java 复制代码
package com.yhh.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev") //指定多环境配置类标识
public class DveConnector implements DBConnector {
    @Override
    public void configure() {
        System.out.println("数据库配置环境dev");
    }
}
java 复制代码
package com.yhh.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("test") //指定多环境配置类标识
public class TestConnector implements DBConnector {
    @Override
    public void configure() {
        System.out.println("数据库配置环境test");
    }
}
java 复制代码
package com.yhh.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("prod") //指定多环境配置类标识
public class ProdConnector implements DBConnector {
    @Override
    public void configure() {
        System.out.println("数据库配置环境prod");
    }
}

上述三个实现类都使用了@Configuration和@Profile注解,其中,@Configuration注解将实现类声明为配置类,可以保证SpringBoot自动扫描并识别;@Profile注解用于进行多环境配置,并通过属性表示配置环境。

接着在全局配置文件application.properties中设置spring.profiles.active属性激活使用@Profile注解构建的多环境配置。

为了测试@Profile注解多环境配置的效果,在项目的controller包中创建一个表示数据库连接配置的DBController类进行测试

java 复制代码
package com.yhh.controller;

import com.yhh.config.DBConnector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DBController {
    @Autowired
    DBConnector connector;

    @GetMapping("/showDB")
    public void show(){
        connector.configure();
    }
}

@Autowired注解用于注入DBConnector,@GetMapping("/showDB")注解用于映射GET请求,这里用来映射路径为"/showDB"的请求.

启动项目的启动类,查看控制台输出显示端口的切换结果

接着在浏览器上访问"http://localhost:8081/showDB" 查看控制台输出效果

控制台的端口号为8081,并打印除指定表示为dev的数据库配置信息,也就是说程序执行了数据库连接配置方法configure().由此可知无论使用Profile文件还是@Profile注解类都可以进行多环境配置,而且相互之间不会干扰

2.5 随机值设置以及参数间引用

在SpringBoot配置文件中设置属性时,除了可以像以上项目中显示的配置属性值外,还可以使用随机值和参数间引用对属性值进行设置。希迈纳我们针对配置文件中这两种属性值的设置方式及逆行详细讲解。

  1. 随机值设置

    在SpringBoot配置文件中,随机值设置使用到了SpringBoot内嵌的RandomValuePropertySource类,对一些隐秘属性值或者测试用例属性值进行随机值注入。

    随机值设置的语法格式为${random.xx},xx表示需要指定生成的随机数类型和范围,它可以生成随机的整数,通用唯一识别码(UUID)或字符串

java 复制代码
my.string=${random.value}  #配置随机字符串
my.number=${random.int}  #配置随机的整数
my.bignumber=${random.long} #配置随机long类型数
my.uuid=${random.uuid}  #配置随机UUID类型数
my.number.less.than.ten=${random.int(10)}  #配置小于10的随机整数
my.number.in.range=${random.int[1024,65536]} #配置范围在[1024,65536]之间的随机整数

上述代码中,使用RandomValuePropertySource类中random提供的随机数类型,分别展示了不同类型随机值的设置示例。

  1. 参数见引用

在SpringBoot配置文件中,配置文件的属性值还可以进行参数间的引用,也就是说,先前定义的属性可以被引用,并且配置文件可以解析引用的属性值。使用参数间引用的好处就是,在多个具有相互关联的配置属性中,只需要对其中一处属性预先配置,其他地方都可以引用,省去了后续多出修改的麻烦。

参数间引用的语法格式为${xx},xx表示先前在配置文件中已经配置过的属性名

java 复制代码
app.name=MyApp
app.description=${app.name} is a SpringBoot application

在上述参数间引用设置代码中,先设置了app.name=MyApp,将app.name属性的属性值设置为了MyApp;接着,在app.description属性配置中,使用${app.name}对前一个属性值进行了引用。

接下来我们通过一个项目来演示,在项目的全局配置文件application.properties中分别通过随机值和参数间引用的方式添加两个测试属性

java 复制代码
# 随机值设置以及参数间引用配置
tom.age=${random.int[10,20]}
tom.description=Tom 的年龄可能是${tom.age}

在上述application.properties配置文件中,先使用随机值设置tom.age属性的属性值,该属性值设置在了[10,20]之间,随后使用参数间引用配置了tom.description属性。

在项目的测试类中定义属性description属性,并使用@Value注解注入tom.description属性。

这里发现一个问题,测试类测试的时候加载application.properties文件中的中文数据会产生乱码,这里需要解决。

后来通过查询了很多资料,是说因为Springboot项目中@Value注解加载application.properties中的中文属性默认的编码格式为ISO-8859-1格式,需要将该格式转换成UTF-8格式,

java 复制代码
String s = new String(description.getBytes("ISO-8859-1"), "UTF-8");

但并没有解决,最后还是在属性放置application.yaml文件中,应该该文件中的所有字符默认为UTF-8格式,因此就不存在中文乱码问题

java 复制代码
# 对实体类对象Person进行属性配置
person:
  id: 2
  name: 张三
  hobby: [sing,read,sleep]
  family: [father,mother]
  map: {k1: v3,k2: v4}
  pet: {type: cat,name: tom}

tom:
  age: ${random.int[10,20]}
  description: Tom 的年龄可能是${tom.age}

当多次运行,可以观察到age的值会在[10-20]之间产生随机数。

本章小结

本章主要讲解了SpringBoot的核心配置与注解,包括全局配置的使用,配置文件属性值的注入,SpringBoot自定义配置,多环境配置,随机值设置以及参数间引用。

习题

一、填空题

  1. 默认情况下,SpringBoot生产的全局配置文件( ).

  2. SpringBoot项目中,application.yaml文件使用( )格式配置属性。

  3. SpringBoot提供的( )注解可以批量将配置文件的属性注入Bean对象。

  4. 使用( )注解注入配置文件属性时,支持SpEL表达式语法。

  5. SpringBoot中能够使用( )注解进行多环境配置。

二、判断题

  1. application.yaml配置文件的属性类型只能时数组类型。( )

  2. 使用@ConfiggurationProperties注解注入属性值时,必须为对应的属性提供setter方法。( )

  3. @Value注解时SpringBoot提供的,用来读取配置文件的属性并能够批量注入Bean。( )

  4. @Value注解支持所有数据类型的属性读取和注入。( )

  5. SpringBoot可以使用@PropertiesResource注解引入XML配置文件。( )

三、选择题

  1. 下列关于SpringBoot全局配置文件的说法,正确的是( ).(多选)

    A.SpringBoot支持application.properties全局配置文件

    B.SpringBoot支持application.yaml全局配置文件

    C.SpringBoot支持application.yml全局配置文件

    D.SpringBoot全局配置文件必须在项目resouces根目录下

  2. 下列关于YAML配置文件的说法,正确的是( ).

    A.YAML配置文件的内容是"key:value"形式的键值对,并使用缩进式写法

    B.YAML配置文件的行内式写法配置单列集合属性,包含属性值的中括号"[]"可以省略

    C.YAML配置文件的行内式写法配置单列集合属性,包含属性值的中括号"{}"可以省略

    D.以上都不对

  3. 下列关于@ConfiggurationProperties注解的说法中,正确的是( ).

    A.@ConfiggurationProperties注解只能作用于类

    B.使用@ConfiggurationProperties注解为Bean注入属性时,必须为Bean设置seter方法

    C.@ConfiggurationProperties注解必须和@Componet结合使用

    D.要想使@ConfiggurationProperties注解注入的属性生效,必须使用@EnableConfigurationProperties注解开启注入

  4. 下列关于@ConfiggurationProperties和@Value注解的说法,正确的是( )

    A.@ConfiggurationProperties和@Value注解都是SpringBoot框架自带的

    B.进行属性值注入时,@ConfiggurationProperties和@Value注解配置中必须设置属性的setter方法

    C.@ConfiggurationProperties注解进行配置文件属性值注入时,支持JSR303数据校验

    D.@Value注解进行配置文件属性值注入时,支持松散绑定语法

  5. 下列关于SpringBoot的Profile多环境配置的说法,错误的是( ).

    A.SpringBoot提供了两种多环境配置的方式:Profile文件多环境配置和@Profile注解多环境配置

    B.Profile配置文件的名必须满足application-{profile}.properties的格式

    C.可以在项目全局配置文件中配置spring.profiles.active属性激活指定的多环境配置文件

    D.在多个自定义类上直接使用@Profile注解可以进行多环境配置

相关推荐
rzl0210 分钟前
java web5(黑马)
java·开发语言·前端
君爱学习16 分钟前
RocketMQ延迟消息是如何实现的?
后端
guojl30 分钟前
深度解读jdk8 HashMap设计与源码
java
Falling4233 分钟前
使用 CNB 构建并部署maven项目
后端
guojl35 分钟前
深度解读jdk8 ConcurrentHashMap设计与源码
java
程序员小假44 分钟前
我们来讲一讲 ConcurrentHashMap
后端
爱上语文1 小时前
Redis基础(5):Redis的Java客户端
java·开发语言·数据库·redis·后端
A~taoker1 小时前
taoker的项目维护(ng服务器)
java·开发语言
萧曵 丶1 小时前
Rust 中的返回类型
开发语言·后端·rust