Spring Boot 技术探索

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

11、Spring Boot中配置文件的使用

平台环境:

名称

版本号

Mac OS X

10.14.5

JDK

1.8.0_201

Apache Maven

3.6.0

IntelliJ IDEA

2019.1 (Ultimate Edition)

Spring Boot

2.1.6.RELEASE

 

  Spring Boot提供了两种格式的配置文件,一种是默认的application.properties,另一种是需要自己创建的application.yml

但是注意:如果application.properties和application.yml同时存在且里面配置相同,则application.properties的配置会覆盖application.yml。

 

一、入门Demo

1、打开src/main/resources/application.properties,写入配置内容

com.example.demo.title=冬夜读书示子聿 作者:陆游
com.example.demo.description=纸上得来终觉浅,绝知此事要躬行。
com.example.demo.keywords=中华古诗词

 

如果使用如果yml格式,则自己新建application.yml文件,并写入代码:

com:
  example:
     demo:
        name: 回乡偶书 
        author: 作者:贺知章
        content: 少小离家老大回,乡音无改鬓毛衰。儿童相见不相识,笑问客从何处来。

 

可以看到,yml配置文件结构清晰,层次分明。

但是!这里需要注意:

  • yml文件必须是UTF-8编码格式
  • 每行缩进字符都要用空格符,不能用tab字符缩进
  • 每个配置项的冒号后边要跟一个空格符

 

2、新建测试类

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest
{
    @Value("${com.example.demo.keywords}")
    private String keywords;

    @Test
    public void testProperties()
    {
        System.out.println(keywords);
    }
}

 

3、执行测试

发现打印出来的是乱码。截图:

 

解决办法:

第一步,找到IntelliJ IDEA——Preferences——Editor——File Encofings菜单,将 Properties Files (*.properties) 下的 Default encoding for properties files 设置为 UTF-8(而不是<System Default:UTF-8>),并选中 Transparent native-to-ascii conversion 复选框。

第二步,找到你正在使用的application.properties或者application.yml,打开编辑一下(例:改成中华古诗词1)关闭,此时IDEA会自动保存。然后再打开,删掉刚刚输入的字符。

 

4、再次执行测试

输出:

中华古诗词1

 

二、通过配置类进行简化

在之前的Demo中,每个需要使用配置文件内容的地方都要重复的@Value注释一遍,能不能简便一点?可以。

 

新建一个配置文件类用@Component注释,并用@Value注入到类的成员变量中。

package com.example.demo.config;

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

@Component
public class AppProperties
{
    @Value("${com.example.demo.title}")
    private String title;

    @Value("${com.example.demo.description}")
    private String description;
    @Value("${com.example.demo.keywords}")
    private String keywords;

    public String getTitle()
    {
        return title;
    }

    public String getDescription()
    {
        return description;
    }

    public String getKeywords()
    {
        return keywords;
    }
}

 

打开之前编写的测试ConfigTest测试类,并修改为以下代码:

package com.example.demo;

import com.example.demo.config.AppProperties;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest
{
    @Resource
    AppProperties appProperties;
    
    @Value("${com.example.demo.keywords}")
    private String keywords;

    @Test
    public void testProperties()
    {
        // 直接获取@Value注入的值
        System.out.println(keywords);
        
        // 通过从Spring管理的类中获取配置文件类AppProperties实例,进而获取配置项的值
        System.out.println(appProperties.getTitle());
        System.out.println(appProperties.getDescription());
    }
}

 

执行测试

中华古诗词1
冬夜读书示子聿 作者:陆游
纸上得来终觉浅,绝知此事要躬行。

 

三、通过@ConfigurationProperties进一步简化

上一步的方法中仍然要在@Component类中使用@Value,能不能在简化一点?可以的。

 

修改配置文件,增加2条新的配置项。

com.example.demo.title=冬夜读书示子聿 作者:陆游
com.example.demo.description=纸上得来终觉浅,绝知此事要躬行。
com.example.demo.keywords=中华古诗词

codelab.bj=北京
codelab.sh=上海

 

新建配置类

package com.example.demo.config;

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

@Component
@ConfigurationProperties(prefix = "codelab")
public class AppProperties2
{
    private String bj;
    private String sh;

    public String getBj()
    {
        return bj;
    }

    public void setBj(String bj)
    {
        this.bj = bj;
    }

    public String getSh()
    {
        return sh;
    }

    public void setSh(String sh)
    {
        this.sh = sh;
    }
}

 

注意,这里使用了@ConfigurationProperties注解。这个注解自动把参数prefix配置的项目赋值到对应的类的属性中。例如codelab.bj会自动赋值到属性bj中。

 

测试:

package com.example.demo;

import com.example.demo.config.AppProperties;
import com.example.demo.config.AppProperties2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest
{
    @Resource
    AppProperties appProperties;

    @Resource
    AppProperties2 appProperties2;


    @Value("${com.example.demo.keywords}")
    private String keywords;

    @Test
    public void testProperties()
    {
        // 直接获取@Value注入的值
        System.out.println(keywords);

        // 通过从Spring管理的类中获取配置文件类AppProperties实例,进而获取配置项的值
        System.out.println(appProperties.getTitle());
        System.out.println(appProperties.getDescription());
    }

    @Test
    public void testProperties2()
    {
        System.out.println(appProperties2.getBj());
        System.out.println(appProperties2.getSh());
    }

}

 

执行测试

北京
上海

 


 

如果配置文件是多层次的,则要通过内部类的形式获取配置值。

 

修改配置文件如下

com.example.demo.title=冬夜读书示子聿 作者:陆游
com.example.demo.description=纸上得来终觉浅,绝知此事要躬行。
com.example.demo.keywords=中华古诗词
codelab.bj=北京
codelab.sh=上海
codelab.province.hb=河北
codelab.province.sd=山东

 

修改配置类如下

package com.example.demo.config;

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

@Component
@ConfigurationProperties(prefix = "codelab")
public class AppProperties2
{
    private String bj;
    private String sh;
    
    @NestedConfigurationProperty
    private Province province;

    public static class Province
    {
        private String hb;
        private String sd;

        public String getHb()
        {
            return hb;
        }

        public void setHb(String hb)
        {
            this.hb = hb;
        }

        public String getSd()
        {
            return sd;
        }

        public void setSd(String sd)
        {
            this.sd = sd;
        }
    }


    public String getBj()
    {
        return bj;
    }

    public void setBj(String bj)
    {
        this.bj = bj;
    }

    public String getSh()
    {
        return sh;
    }

    public void setSh(String sh)
    {
        this.sh = sh;
    }

    public Province getProvince()
    {
        return province;
    }

    public void setProvince(Province province)
    {
        this.province = province;
    }
}

 @NestedConfigurationProperty的作用是用来修饰一个嵌套类的字段,把这个类视作常规类,而非内部类。

 

修改测试类如下

package com.example.demo;

import com.example.demo.config.AppProperties;
import com.example.demo.config.AppProperties2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest
{
    @Resource
    AppProperties appProperties;

    @Resource
    AppProperties2 appProperties2;


    @Value("${com.example.demo.keywords}")
    private String keywords;

    @Test
    public void testProperties()
    {
        // 直接获取@Value注入的值
        System.out.println(keywords);

        // 通过从Spring管理的类中获取配置文件类AppProperties实例,进而获取配置项的值
        System.out.println(appProperties.getTitle());
        System.out.println(appProperties.getDescription());
    }

    @Test
    public void testProperties2()
    {
        System.out.println(appProperties2.getBj());
        System.out.println(appProperties2.getSh());

        System.out.println(appProperties2.getProvince().getHb());
        System.out.println(appProperties2.getProvince().getSd());

    }

}

 

执行测试

北京
上海
河北
山东

 

 

四、如何自定义配置文件?

新建配置文件other.properties

内容:

codelab.bj=beijing
codelab.sh=shanghai

 

新建配置类

package com.example.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "codelab")
@PropertySource("classpath:other.properties")
public class AppProperties3
{
    private String bj;
    private String sh;
    public String getBj()
    {
        return bj;
    }
    public void setBj(String bj)
    {
        this.bj = bj;
    }
    public String getSh()
    {
        return sh;
    }
    public void setSh(String sh)
    {
        this.sh = sh;
    }
}

 

修改测试文件

package com.example.demo;
import com.example.demo_web2.config.AppProperties;
import com.example.demo_web2.config.AppProperties2;
import com.example.demo_web2.config.AppProperties3;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigTest
{
    @Autowired
    AppProperties appProperties;
    @Resource
    AppProperties2 appProperties2;
    @Resource
    AppProperties3 appProperties3;
    @Value("${com.example.demo.keywords}")
    private String keywords;
    @Test
    public void testProperties()
    {
        // 直接获取@Value注入的值
        System.out.println(keywords);
        // 通过从Spring管理的类中获取配置文件类AppProperties实例,进而获取配置项的值
        System.out.println(appProperties.getTitle());
        System.out.println(appProperties.getDescription());
    }
    @Test
    public void testProperties2()
    {
        System.out.println(appProperties2.getBj());
        System.out.println(appProperties2.getSh());
        System.out.println(appProperties2.getProvince().getHb());
        System.out.println(appProperties2.getProvince().getSd());
    }
    @Test
    public void testProperties3()
    {
        System.out.println(appProperties3.getBj());
        System.out.println(appProperties3.getSh());
    }
}

 

执行测试,发现并没有生效。

北京
上海

 

原因:

如果自定义配置文件中的配置项和application.properties中的一样,则系统默认的配置文件会覆盖掉自定义配置文件的内容。即使加注了@PropertySource("classpath:other.properties”)也没用。

 

修改自定义配置文件

other.bj=beijing
other.sh=shanghai

 

修改配置类

package com.example.demo.config;

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

@Component
@ConfigurationProperties(prefix = "other")
@PropertySource("classpath:other.properties")
public class AppProperties3
{
    private String bj;
    private String sh;

    public String getBj()
    {
        return bj;
    }

    public void setBj(String bj)
    {
        this.bj = bj;
    }

    public String getSh()
    {
        return sh;
    }

    public void setSh(String sh)
    {
        this.sh = sh;
    }
}

 

执行测试

beijing
shanghai

 

 

五、多配置文件切换

背景:

有时候不同运行环境需要加载不同的参数,例如生产环境和测试环境。此时可以定义两个配置文件。通过运行时参数来控制使用哪个。

 

新建配置文件application-dev.properties

com.example.demo.name=这是生产环境

 

新建配置文件application-test.properties

com.example.demo.name=这是测试环境

 

新建测试控制器

package com.example.demo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController

public class WebController
{
    @Value("${com.example.demo.name}")
    private String demoName;

    @RequestMapping("/testConfig")
    public String getConfig()
    {
        return demoName;
    }

}

 

打开IDEA的Terminal窗口:

定位到pom文件路径下,输入

mvn clean package

意思是把当前项目以jar包形式打包到target目录下。

 

此时报错:

 

往上翻,找到原因:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webController2': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'com.example.demo.name' in value "${com.example.demo.name}"

意思是说找不到配置项com.example.demo.name

 

为什么没有找到呢?在往上翻看:

2019-07-11 14:53:45.632  INFO 23446 --- [           main] com.example.demo.DemoApplicationTests    : No active profile set, falling back to default profiles: default

因为mvn打包测试时没有指定参数,所以加载了默认application.properties配置文件。而默认文件中没有指定com.example.demo.name配置项。

 

增加跳过测试参数打包

mvn clean package -Dmaven.test.skip=true

 

使用java -jar命令启动项目

java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev

 

浏览器访问http://localhost:8080/testConfig

显示

这是生产环境

 

在Terminal窗口按Control+C停止服务

再次使用java -jar命令启动项目

java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=test

 

浏览器访问http://localhost:8080/testConfig

显示

这是测试环境

 

Bootstrap Thumbnail Second
MySQL

MySQL is the world's most popular open source database.

GO

Bootstrap Thumbnail Third
算法基础

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。

GO