SpringBoot之配置文件

本文最后更新于:2021年3月13日 晚上

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. 参考链接