项目中读取配置文件中内容时最常用的方法就是使用@Value注解;对于非官方指定的配置类文件,则需要借助@PropertySource注解实现注入;而在配置类中读取一组配置属性时还可以通过@ConfigurationProperties注解指定统一的前缀内容。
1. 使用@Value注解
@Value注解使用时会优先读取默认配置文件application.properties中定义的属性。
- 使用方式为:
@value("${server.port}") - 使用时将注解标注在成员变量上,表示将对应属性值加载到该变量中
- 使用@Value注解时需要注意,如果不满足以下条件时,注入属性的值为null
- 使用了static或final修饰了字段变量,此时在容器注入对象时不会对静态变量赋值
- 类上没有使用@Component或其他将类加入容器的注解,类不在容器中无法注入属性
- 使用new创建了类的示例而不是使用@Autowired,此时不是从容器中获取,无法注入属性
public class Config{
@Value("${server.port}")
private String port;
}
2. @PropertySource
@PropertySource可以用来读取自定义配置文件中定义的属性。
- 该注解可以标注在类或者接口上,设置当前类的属性读取对应的配置文件内容
- 使用方式:
@PropertySource(value={"classpath:/other.properties"}) - 此时在类中属性上使用注解@Value("name"),读取的就是指定配置文件中的值
- 注意,如果默认配置文件中存在同名属性,则默认配置文件的优先级更高
@PropertySource使用小细节
- @PropertySource加载配置文件是将指定文件同时加入到容器中,而不会覆盖,可以同名
- 通过注解
@PropertySource导入进来的属性源的优先级是最低的 - 加载配置文件时,项目源路径使用
classpath,绝对路径使用file:/src/...
@PropertySource和Environment配合使用
- 使用@PropertySource注解将指定配置文件加入容器中
- 注入Environment对象,通过其
env.getProperty("name.short")来或取指定属性的值
@Configuration
@PropertySource("classpath:test.properties")
public class TestConfig {
@Autowired
private Environment env;
public void test(){
String shortName = env.getProperty("name.short");
}
}
3. 使用@ConfigurationProperties注解
@ConfigurationProperties注解可以为配置类的属性变量指定配置文件中对应的属性前缀。
- 使用方式:
@ConfigurationProperties(prefix = "user") - 此时会使用默认配置文件中以user开头的属性
- 定义属性变量时,如果类变量与配置文件属性同名,则可以不使用@Value注解
- 也可以与
@PropertySource配合使用,加载非默认配置文件中属性
@ConfigurationProperties(prefix = "user")
public class Config{
// user.name
private String name;
}
4. 为什么Spring容器不能注入静态变量
静态变量和静态方法属于类,而Spring容器中管理的是对象,因此使用@Autowired注入的是容器中的对象实例,所以静态方法是不能直接使用@Autowried注入的。
在使用@Value读取配置文件属性时也是类似,配置文件内容会作为Properties对象的属性管理在容器中,使用注解加载到变量上时就是使用了容器注入的机制。
因此 @Value 注解标注在 static 或 final 变量时,并不能将属性值注入,得到的值是 null。
4.1 @Autowired不能注入static成员属性的原因
Spring 不建议开发代码中为静态变量注入属性值,类加载时会优先加载静态变量,此时 Spring 的上下文环境还没有完成加载,因此不可以为静态变量绑定值。
另一方面,在 @Autowired 注解注入扫描 Class 类原数据时,会直接忽略类的使用 static 关键字标识的成员。
4.2 set 方法注入
如果想要为static变量注入值,可以间接的操作方式,比如可以通过注解标注在 set 方法(非静态)上,使用set方法注入的方式将属性值赋值到静态变量中。
@Component
public class Customer {
private static String name;
@Value("${customer.name}")
public void setName(String name) {
Customer.name = name;
}
}
如果是定义工具类,不建议在工具类中使用注入的内容,因为工具类定义的是静态方法,使用时容器并没有加载完成,会出现问题。