SpringBoot配置文件注入属性(将常修改的配置属性提取到外部配置文件中)
1.需求分析
在日常团队开发中,经常需要在本地、测试服务器、云端服务器之间来回切换进行开发与测试,而项目中可能有大量的地方需要配置服务器 IP、WebSocket 连接地址等信息,为了方便修改这些配置属性,可以将他们提取到外部配置文件中进行统一管理。这样,即使项目上线,也可以在项目所在目录直接修改配置文件信息,而不需要重新下线、修改、打包、测试、上线。
2.属性注入
Spring为属性注入提供了一个注解 @ConfigurationProperties
,其属性 prefix
用于指定属性前缀。例如:
@Data // Lombok 工具
@ConfigurationProperties(prefix = "stu") // 这里指定,Student 类会默认加载配置文件中,所有以 stu 开头的属性,并自动注入到对应名称的属性
public class Student {private String name;private String id;private int age;
}
但 @ConfigurationProperties
注解不是立即生效的,他的前提条件是,必须将该类注入为 Spring 的一个 Bean,接受 Spring 的管理,才能使用属性注入功能。一般来说,有两种方式:
-
在该类上使用
@Component
或@Configure
等注解,将该类标记为 Spring 的一个 Bean -
与
@EnableConfigurationProperties
注解配合使用
2.1.使用 @Component
或 @Configure
等注解
这种方式最方便,并且能够同时支持默认配置文件 application.properties
(.yaml
格式也是一样的)与自定义配置文件(例如我自定义一个 student.properties
)
例:
@Data // Lombok 工具
@ToString // Lombok 工具
/*** 将 Student 类标记为一个 Bean 注入到 Spring 中* 这里使用 @Configure 注解也可以,因为这个注解中也包含一个 @Component* 要使用其他的,如 @Service,@Controller 也可以,但一般不会这么用*/
@Component
@ConfigurationProperties(prefix = "stu")
public class Student {private String name;private String id;private int age;
}
此时,默认配置文件 application.properties
中配置对应的属性,就会自动注入到 Student 类对应的 Bean 中,如下:
# 这是 application.properties
stu.name=lisi
stu.id=5422
stu.age=22
测试一下:
@SpringBootTest // 标记为 Springboot 测试类,即可以使用 Spring 自动注入等功能
@RunWith(SpringRunner.class) // 需要与 @SpringBootTest 注解一起使用
@Slf4j // log4j 日志工具
public class MainTest {@Autowiredprivate Student student;@Testpublic void test() {if(student == null)log.info("MainTest :: test() :: student is null");elselog.info("MainTest :: test() :: student: " + student.toString());}
}// 输出结果 //
// MainTest :: test() :: student: Student(name=lisi, id=5422, age=22)
可见,默认配置文件中的配置属性都注入到了 Student 类中对应名称的属性上。
同时,我们可以使用 @PropertySource
注解指定自定义的外部配置文件:
@Data // Lombok 工具
@ToString // Lombok 工具
@Component
@ConfigurationProperties(prefix = "stu")
/*** 指定一个自定义的配置文件: 类路径下的 extraConfig/student.properties*/
@PropertySource(value = {"classpath:extraConfig/student.properties"})
public class Student {private String name;private String id;private int age;
}
在项目中创建一个 resources.extraConfig
文件下,用于统一管理自定义配置文件,在下面建一个 student.properties
配置文件:
编写配置文件:
# 这是 student.properties
stu.name=zhangsan
stu.id=5403999321
同时修改默认配置文件 applicaiton.properties
:
# 这是 applicaiton.properties
stu.id=123
stu.age=22
测试一下:
@SpringBootTest // 标记为 Springboot 测试类,即可以使用 Spring 自动注入等功能
@RunWith(SpringRunner.class) // 需要与 @SpringBootTest 注解一起使用
@Slf4j // log4j 日志工具
public class MainTest {@Autowiredprivate Student student;@Testpublic void test() {if(student == null)log.info("MainTest :: test() :: student is null");elselog.info("MainTest :: test() :: student: " + student.toString());}
}// 输出结果 //
// MainTest :: test() :: student: Student(name=zhangsan, id=123, age=22)
可以发现,Student 类的 Bean 同时读取了 application.preperties
和 student.properties
配置文件中对应的属性值,但 application.preperties
的优先级更高,当 application.preperties
中没有的属性,Spring 才会到自定义的 student.properties
中去找。
2.2.使用 @EnableConfigurationProperties
注解
该注解也是将对应的实体类,标注为 Spring 的一个 Bean 交给它去管理,因此,只要是 @EnableConfigurationProperties
指定的类,不需要 @Component
等注解,一样会被 Spring 管理,并且其 @ConfigurationProperties
也会生效。
不过要注意以下几点:
- 如果要使用
@EnableConfigurationProperties
注解在其他类控制该实体类的注入,那么在该实体类上,就不要再使用@Component
等注解了,虽然不会冲突,但这么做就没有什么意义了,不符合逻辑。 - 使用
@EnableConfigurationProperties
注解,则读取不到自定义配置文件中的属性值,只能读到默认配置文件application.preperties
中的属性值 - 一般不会使用这种方式,
@EnableConfigurationProperties
注解一般是第三方源代码提供给用户的注入方式
测试一下:
@SpringBootApplication
/*** 使用 @EnableConfigurationProperties 注解注入 Student 类,使其* @ConfigurationProperties 注解生效*/
@EnableConfigurationProperties(Student.class)
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}
@Data
@ToString
//@Component // 不再使用 @Component 注解
@ConfigurationProperties(prefix = "stu")
@PropertySource(value = {"classpath:extraConfig/student.properties"})
public class Student {private String name;private String id;private int age;
}
@SpringBootTest // 标记为 Springboot 测试类,即可以使用 Spring 自动注入等功能
@RunWith(SpringRunner.class) // 需要与 @SpringBootTest 注解一起使用
@Slf4j // log4j 日志工具
public class MainTest {@Autowiredprivate Student student;@Testpublic void test() {if(student == null)log.info("MainTest :: test() :: student is null");elselog.info("MainTest :: test() :: student: " + student.toString());}
}// 输出结果 //
// MainTest :: test() :: student: Student(name=null, id=123, age=22)
由结果可见,使用 @EnableConfigurationProperties(Student.class)
,Spring 在注入 Student 类的 Bean 时,读取到了 application.properties
中的相应的配置属性,但 student.properties
里配置的 stu.name
和 stu.id
就读取不到了。