SpringBoot之配置文件

1. 什么是配置文件?

当我们构建完Spring Boot项目后,会在resources目录下给我们一个默认的全局配置文件 application.properties,这是一个空文件,因为Spring Boot在底层已经把配置都给我们自动配置好了,当在配置文件进行配置时,会修改SpringBoot自动配置的默认值。

2. 配置文件有什么用?

  • 修改SpringBoot自动配置的默认值,使我们程序的插件能正常运行(比如Mysql、mybatis配置)。
  • 自定义配置属性,便于我们维护程序中的变量值。

3. 配置文件的种类

3.1 .yml(推荐使用)

  • YAML:一种标记语言,以数据为中心,比JSON、XML更适合做配置文件,后缀名可以是 .yml.yaml
  • 在SpringBoot中,使用最广泛的配置文件是它,yaml之所以流行,除了他配置语法精简之外,还因为yaml是一个跨编程语言的配置文件 。
  • 基本语法
    • k:(空格)v;其中k是键,v是值,注意冒号后面有个空格。
    • 以空格的缩进为控制层级关系, 左对齐 的一列数据的层级关系是一样的。
    • 属性和值都是大小写敏感的。
  • .yml配置Tomcat启动端口号示例
server:
  port: 8081

3.2 .properties

  • 以key=value格式存储内容的文件。
server.port=8081

3.3 .xml

  • 传统的Spring配置文件格式。
  • 因为其配置繁琐、开发效率稍低、文件解析耗时等原因,.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="xmlTest" class="com.liang.stu.properties.core.XmlTest">
        <property name="stringTest" value="abc"/>
        <property name="listTest" value="a,b,c"/>
        <property name="mapTest">
            <map>
                <entry key="a" value="1"/>
                <entry key="b" value="2"/>
            </map>
        </property>
    </bean>
</beans>

4. SpringBoot配置文件读取优先级

4.1 三种比较方式

  • 文件名优先级
application > bootstrap
  • 路径优先级
1. file:./config/           (项目根目录中config目录下)
2. file:./                  (项目根目录下)
3. classpath:/config/       (项目resources目录中config目录下)
4. classpath:/              (项目的resources目录下)

如下图所示
路径优先级

  • 类型优先级
.properties > .yml

4.2 小结

  • 三种优先级比较时,只有前者相同,才需比较后面的 文件名优先级 > 路径优先级 > 类型优先级
  • 经过测试发现:springboot项目默认并不能读取到bootstrap配置文件,必须加入spring-cloud-context的依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-context</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
  • 所以bootstrap是在cloud项目中才使用的配置文件
  • bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取. 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
    application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等.如果加载的application.yml的内容标签与bootstrap的标签一致,application会覆盖bootstrap, 而application.yml 里面的内容可以动态替换。
  • 经过测试发现:配置文件放在项目根目录下时只有是自定义的属性配置才会生效,(比如非自定义的server.port=8081配置不会生效)。
    看到这篇博客的人知其原因可留言告知,非常感谢。

5. SpringBoot获取配置文件属性的方法

  • 假设有一个 application.yml 配置信息如下
com:
  stringTest: abc
  listTest: a,b,c

5.1 通过 @Value 注解将对应的属性注入到field上

  • 必须将实体类交由SpringBoot自动装配到Spring容器中。使用时依赖注入
@Getter
@Component
public class ValueTest {
    @Value("${com.stringTest}")
    private String stringTest;
    @Value("${com.listTest}")
    private List<String> listTest;
}
  • 编写测试类
@SpringBootTest
public class ValueTests {

    @Resource
    private ValueTest valueTest;

    @Test
    public void test() {
        System.out.println(valueTest.getStringTest());
        System.out.println(valueTest.getListTest());
    }
}
  • 运行结果
abc
[a, b, c]

5.2 通过 @ConfigurationProperties 将属性映射给类的属性

@ConfigurationProperties注解只会映射已经被SpringBoot读取的配置文件。

如果你的 .properties 配置还未被SpringBoot读取,可以使用@PropertySource指定。

如果你的 application-*.yml 配置还未被SpringBoot读取,可以在application.yml里加入以下配置使SpringBoot读取。

spring:
  profiles:
    active: common,wx
  • 创建PropertySourceTest实体类接收属性映射
@Configuration
@ConfigurationProperties(prefix = "com") //指定前缀
@PropertySource(value = "classpath:test.properties", encoding = "UTF-8") //额外指定需要读取的文件和读取格式
public class PropertySourceTest {

    private static String stringTest;

    public static String getStringTest() {
        return stringTest;
    }

    public void setStringTest(String stringTest) {
        PropertySourceTest.stringTest = stringTest;
    }
}
  • 编写测试类
@Test
public void test() {
    System.out.println(PropertySourceTest.getStringTest());
}
  • 运行结果
abc
  • 使用 @ConfigurationProperties 方式可以进行配置文件与实体字段的自动映射,但需要字段必须提供set方法才可以。
  • 使用 @Value 注解修饰的字段不需要提供set方法。

5.3 利用 Environment (org.springframework.core.env.Environment)

  • 直接引入Environment即可
@SpringBootTest
public class EnvironmentTests {

    @Resource
    private Environment env;

    @Test
    public void test() {
        System.out.println(env.getProperty("com.stringTest"));
        System.out.println(env.getProperty("com.listTest"));
    }

}
  • 运行结果
abc
a,b,c

5.4 通过工具类

5.4.1 .yml 属性文件读取

  • 利用 org.yaml.snakeyaml 包下的 Yaml 读取配置文件从而获得对应的配置信息。
  • 创建 YamlUtil 工具类。
@Slf4j
public class YamlUtil {

    private static Map<String, Object> ymlMap = new HashMap<>();

    public YamlUtil(String location) {
        ymlMap = getYmlMap(location);
    }

    public static YamlUtil getInstance(String location) {
        return new YamlUtil(location);
    }

    public static Map<String, Object> getYmlMap(String location) {
        try {
            Yaml yaml = new Yaml();
            log.info("开始加载资源:{}", location);
            InputStream in = YamlUtil.class.getClassLoader().getResourceAsStream(location);
            return yaml.loadAs(in, HashMap.class);
        } catch (Exception e) {
            log.error("加载资源:{}失败,发生IOException异常,异常信息为:{}", location, e.getMessage(), e);
        }
        return null;
    }

    public String getString(String key) {
        String separator = ".";
        if (!key.contains(separator)) {
            return ymlMap.get(key).toString();
        }
        String[] keys = key.split("\\.");
        Map<String, Object> finalMap = new HashMap<>();
        for (int i = 0; i < keys.length - 1; i++) {
            if (i == 0) {
                finalMap = (Map<String, Object>) ymlMap.get(keys[0]);
                continue;
            }
            if (finalMap == null) {
                return null;
            }
            finalMap = (Map<String, Object>) finalMap.get(keys[i]);
        }
        if (finalMap == null) {
            return null;
        }
        return finalMap.get(keys[keys.length - 1]).toString();
    }

}
  • 编写测试类
@Test
public void test3() {
    System.out.println(YamlUtil.getInstance("application.yml").getString("com.stringTest"));
}
  • 运行结果
abc

5.4.2 .properties 属性文件读取

  • 利用 org.springframework.core.io.support 包下的 PropertiesLoaderUtils 读取配置文件从而获得对应的配置信息。
  • 创建 PropertiesUtil 工具类。
@Slf4j
public class PropertiesUtil {

    private final Properties properties;

    public PropertiesUtil(String location) {
        properties = getProperties(location);
    }

    public static PropertiesUtil getInstance(String location) {
        return new PropertiesUtil(location);
    }

    public String getString(String key) {
        return properties.getProperty(key);
    }

    public static Properties getProperties(String location) {
        try {
            log.info("加载资源文件:{}", location);
            return PropertiesLoaderUtils.loadProperties(
                    new EncodedResource(
                            new ClassPathResource(location), "UTF-8"));
        } catch (IOException e) {
            log.error("加载资源:{}失败,发生IOException异常,异常信息为:{}", location, e.getMessage(), e);
        }
        return null;
    }

}
  • 编写测试类
@Test
public void test3() {
    System.out.println(YamlUtil.getInstance("application.yml").getString("com.stringTest"));
}
  • 运行结果
abc

6. .xml配置文件读取

  • .xml 配置文件常用结合 <bean> 标签,将属性值赋给实体类使用。
  • 修改 application.yml 允许bean覆盖。
spring:
  main:
    allow-bean-definition-overriding: true #允许bean覆盖
  • 创建 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="xmlTest" class="com.liang.stu.properties.core.XmlTest">
        <property name="stringTest" value="abc"/>
        <property name="listTest" value="a,b,c"/>
        <property name="mapTest">
            <map>
                <entry key="a" value="1"/>
                <entry key="b" value="2">
                </entry>
            </map>
        </property>
    </bean>
</beans>
  • 创建 XmlTest实体类
public class XmlTest {
    private static String stringTest;
    private static List<String> listTest;
    private static Map<String, Object> mapTest;

    public static String getStringTest() {
        return stringTest;
    }

    public void setStringTest(String stringTest) {
        XmlTest.stringTest = stringTest;
    }

    public static List<String> getListTest() {
        return listTest;
    }

    public void setListTest(List<String> listTest) {
        XmlTest.listTest = listTest;
    }

    public static Map<String, Object> getMapTest() {
        return mapTest;
    }

    public void setMapTest(Map<String, Object> mapTest) {
        XmlTest.mapTest = mapTest;
    }
}
  • 编写测试类
@SpringBootTest
public class XmlTests {
    @Test
    public void test() {
        System.out.println(XmlTest.getStringTest());
        System.out.println(XmlTest.getListTest());
        System.out.println(XmlTest.getMapTest());
    }
}
  • 运行结果
abc
[a, b, c]
{a=1, b=2}

7. 参考链接

  1. 最全面的SpringBoot配置文件详解
  2. Springboot获取配置文件属性的方法
  3. SpringBoot基础-XML方式注册bean