首先打开src/main/resources/application.properties,添加配置:
com.template.name=this is a test name
com.template.age=21
-
用配置类来操作application.properties
在pom.xml中添加一个依赖:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
该依赖的主要作用是:spring-boot-configuration-processor jar中提供了一个编译时调用的Java注解处理器,提供对@ConfigurationProperties注解的支持。
在src/main/java/com/项目名/下添加一个java类,用于application.properties属性的获取和存储。
import org.springframework.stereotype.Component;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Component
@ConfigurationProperties(prefix="com.template")
public class Config {
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注意:
- 使用@Component将该类注解为spring的管理类,也就是将一个java类注入到spring容器中,这样注入到spring中的其他类就可以使用该类了。详见附录。
- 使用@ConfigurationProperties(prefix="com.template")将application.properties中的属性注入到Config类中。其中prefix指定了application.properties中属性的前缀,也就是只有这部分指定的属性才会被注入。Config类的成员变量名与各个指定的application.properties属性名一一对应。例如属性com.template.name,指定了前缀为com.template,那么在Config类中对应的成员变量名就是name。
- @ConfigurationProperties(prefix="com.template")是对整个类进行映射。可以使用@Value("${com.template.xxx}")来对单个值进行映射。详见附录。
- 引用:
@Autowired
private Config cg;
这样就可以使用已注入spring的Config对象cg的值。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.template.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private Config cg;
@RequestMapping("/test")
public JSON index() {
JSON r = new JSONObject();
((JSONObject) r).put("name", cg.getName());
((JSONObject) r).put("age", cg.getAge());
return r;
}
}
整体思路:
- 定义一个Config类,使用@ConfigurationProperties(prefix="com.template")或@Value("${com.template.xxx}")来作为该类的初始化参数值。这样,当该类的实例注入到spring时,就会以application.properties中的值来初始化该实例。
- 为Config类添加@Component注解,这样就会将类注入到spring中。由于1中的设置,注入的Config类实例中各成员变量就是application.properties中的值。
- 在需要使用application.properties值的地方,使用:
@Autowired
private Config cg;
来获取到spring中的Config实例。 - 调用Config实例的get函数来获取具体值。
以上为通用的properties文件读取方式。无论是默认的application.properties还是用户自定义的properties,都可以用上面的方式来读取。但由于上面没有指定数据源,会默认读取application.properties。
-
用配置类来操作自定义配置文件
设在src/main/resources/下,创建了一个config文件夹,下面添加了一个配置文件template.properties。
自定义配置文件使用上面一中的通用方案时,需要在Config类前使用@PropertySource注解设置数据源:
@PropertySource(value = {"classpath:config/template.properties"},ignoreResourceNotFound = false, encoding = "UTF-8", name = "template.properties")
后续的操作就与一完全相同了。
特别注意:自定义的配置文件的内容,与application.properties的内容不能相同,特别是不能出现相同的前缀,否则读出的配置值是application.properties中的,即使通过@PropertySource指定了数据源。
例如:
为src/main/resources/config/template.properties,添加配置:
com.template.name=测试名
com.template.age=21
这个配置与application.properties有相同的前缀,也就是prefix="com.template"。
指定数据源为config/template.properties,编译,运行,都是正常的。但获取到name属性,会发现其值是this is a test name,而非测试名。
修改template.properties的前缀:
config.template.name=测试名
config.template.age=21
同时需要修改:
@ConfigurationProperties(prefix="config.template")
再次获取name属性,会发现其值已经是测试名。
-
用Environment变量操作application.properties
对于默认的application.properties,Spring-Boot本身提供了一个Environment类,且已注入到spring容器中。因此可以直接使用@Autowired获取:
@Autowired
private Environment env;
读取配置时:
String name = env.getProperty("com.template.name");
因此,对于application.properties,使用Environment类更方便。
-
用Environment变量操作自定义配置文件
三中的Environment类,不仅可用于读取默认的application.properties,也可以用于操作自定义配置文件。
Environment类定义如下:
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
boolean acceptsProfiles(String... var1);
}
提供了一个acceptsProfiles()函数。该函数可接受多个逗号隔开的String变量,用于为Environment添加新的配置文件。
例如,要将template.properties加入到Environment中来:
boolean r = env.acceptsProfiles("/config/template.properties");
然后就可以使用key来读取配置:
String name = env.getProperty("config.template.name");
然而这也意味着,不同配置文件中的配置项,key一定不可以重复。
-
通用方案:获取配置文件所有的键值对
上面的一和二,需要对配置文件创建对应的类。这意味着,配置文件的每一个配置项,都要写一个对应的类属性。每增删一个属性,都要同时维护配置文件和对应的类。
上面的三则不存在这些问题,只需要维护一个配置文件,取值的时候传入正确的配置项名即可。推荐使用。
除了上面的方式,还可以获取配置文件所有的键值对并保存,这样也能实现读取配置文件的目的。该方式同时适用于application.properties和用户自定义配置文件。
因为配置文件也是个文件,且其格式是固定的。只要读取配置文件,然后按照其格式进行解析,保存为键值对即可。
实际上,Spring-Boot本身提供了一个Properties类,可用于属性的保存,且接受InputStream作为输入。所以只需要将文件读取为一个InputStream,然后传给Properties对象即可。
Properties prop = new Properties();
try {
InputStream in = Object.class.getResourceAsStream("/config/template.properties");
prop.load(in);
} catch (IOException e) {
e.printStackTrace();
}
String name = prop.getProperty("config.template.name").trim();
如上,即可正确取到自定义的属性config.template.name。
于是,只需要创建一个单件,在程序启动文件中将配置文件进行加载,然后保存所有的键值对。当需要获取配置文件值的时候,调用该单件取其保存的值。
附录
一.关于@Component和@Autowired
在spring框架中,有控制反转和依赖注入的特性。spring实现的方式是:
- 是要求开发者配置一个xml,指定类的名称,路径,以及初始化时传入的参数。
- spring读取该xml,对该类进行实例化,将其实例化对象(而非类)保存在spring容器中,称之为注入。
有的java类需要这样注入到spring容器中,有的不需要。因此,对于需要注入的,添加xml配置;不需要注入的不用添加。
然而这样意味着开发者除了编写java类,还要编写一个配套的xml配置,于是出现了注解@Component。@Component的作用就是告诉spring, 我需要被注入到spring容器中,请按照我自身提供的参数来实例化一个类对象,并放入spring容器中。初始化参数可以通过类的参数默认值定义或者其他注解来提供。详见附录二。
对于已经存在于spring容器中的实例化对象,要引用,同样需要通过xml来配置。例如,一个类Person有一个Car类的属性。实例化类Person时,需要提供Car类的实例化对象做参数。此时,从spring容器中取出已经注入的Car类对象传入即可。
spring的做法,同样是通过xml,来为要实例化的Person类指定已经实例化的Car对象。因为每个实例化的对象都可以定义一个id,所以这个指定可以通过id来进行。
但这样同样意味着需要编写xml。
于是spring提供了@Autowired注解:当需要引用一个spring容器中已注入的类实例时,直接在前面加入@Autowired注解,spring就会自动对已注入的所有类对象进行类型匹配,一旦匹配成功,就直接将其返回。这样就省略掉了xml配置。
这也意味着,spring容器中每个类型的对象有且只有一个。否则,对类型进行匹配后,得到的实例对象为0个或多个,都会报错。
总之,一个类要求按照自身提供的初始化参数进行实例化,并将实例化后的对象注入到spring中,使用@Component;要使用spring中已注入的某个类的实例化对象,使用@Autowired。这两个注解往往配套使用:使用@Component来注入对象,使用@Autowired来使用已注入的对象。
二.类的初始化参数
类的初始化参数最常见的是java所提供的默认值:
public class Config {
public String name = "this is a name";
}
或:
public class Config {
public String name;
public Config() {
name = "this is a name";
}
}
如上,上面两种方式都提供了一个默认的初始化参数name的方式。
对该类添加@Component注解,使用@Autowired来引用后,得到的实例对象是做了对应的初始化的。
@ConfigurationProperties注解的作用是将指定的配置文件映射到该类。也就是:配置文件值→同名类属性。
例如:
配置文件:
com.template.name=this is a test name
类:
@ConfigurationProperties(prefix="com.template")
public class Config {
public String name;
}
这样,@ConfigurationProperties会将com.template.name映射给Config类的属性name。
也就是相当于:
public class Config {
public String name = "this is a name";
}
三.注解
spring常用的注解有4种:
@Controller、@Service、@Repository、@Component
这些注解的作用都是将实例化对象注入到spring容器中,本质上是相同的。
然而,除了注入功能,spring还提供抛出异常功能。不同的层,其异常是不同的,例如Controller层与Service层的异常是不同的。
所以,spring通过对类添加不同的注解,来执行对应的异常处理。
这也是为什么一个Controller类只能添加@Controller注解,而不能添加@Service注解。
四.application.properties映射到类
application.properties映射到类有两种方式:
- @ConfigurationProperties(prefix="com.template")
@ConfigurationProperties(prefix="com.template")
public class Config {
public String name;
public int age = 21;
}
这样,Config类进行spring注入时,就会将application.properties中的值赋给Config类同名的成员变量。
- @Value("${com.template.xxx}")
该方式是对单个值进行映射:
public class Config {
@Value("${com.template.name}")
public String name;
@Value("${com.template.age}")
public int age = 21;
}
这样,Config类进行spring注入时,就会将application.properties中的值一个一个对应地赋给指定的Config类的成员变量。可以名称不同。
注意:@ConfigurationProperties和@Value注解都不可以用于局部变量,也就是不能在方法体内使用这两个注解来初始化对象。