在Spring中从属性文件中读取值
在本文中,我们将介绍如何在Spring中将配置外部化为属性文件,以及如何在XML中使用XML配置和@PropertySource注释从属性文件中读取值。
最佳实践是将应用程序特定的设置放入单独的属性文件中,而不是在配置中对其进行硬编码。例如,可以将与数据库相关的配置属性(例如DB Url,Driver类,用户,密码)存储在属性文件中,然后从该文件中读取或者在用于发送电子邮件的应用程序中读取SMTP设置(例如主机,用户,密码)可以存储在属性文件中。
Spring中使用XML配置的属性文件
我们可以使用XML中的<context:property-placeholder>配置属性占位符。将要替换的值指定为$ {property-name}形式的占位符。在运行时,将PropertySourcesPlaceholderConfigurer应用于元数据,它检查属性文件中的占位符,并替换与属性文件中的键匹配的占位符值。
请注意,在使用从Spring 5.2开始弃用的org.springframework.beans.factory.config.PropertyPlaceholderConfigurer类之前,要从Spring 5.2版开始使用org.springframework.context.support.PropertySourcesPlaceholderConfigurer。
使用<context:property-placeholder>元素时,将自动注册PropertySourcesPlaceholderConfigurer。
例如,有一个app.properties文件保存在/ src / main / resources /位置,因此它位于类路径上。
db.driverClassName=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/theitroad db.username=user db.password=password
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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- For properties files --> <context:property-placeholder location="classpath:app.properties" /> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value = "${db.driverClassName}" /> <property name="url" value = "${db.url}" /> <property name="username" value = "${db.username}" /> <property name="password" value = "${db.password}" /> </bean> </beans>
如我们所见,通过指定属性文件的位置,使用<context:property-placeholder>元素注册了属性文件。
使用XML指定多个属性文件
我们可以将多个属性文件作为逗号分隔的值传递到location属性中
<context:property-placeholder location="classpath:db.properties, classpath:mail.properties" />
使用@PropertySource注释的Spring中的属性文件
还有一个@PropertySource注释,它为将PropertySource添加到Spring的环境中提供了一种方便的声明性机制。
我们可以将@PropertySource注释与@Value注释一起使用,以注入从属性文件读取的值,但是更好的方法是使用Spring的环境。
@PropertySource和@Value注入值
@Configuration @ComponentScan(basePackages = "com.theitroad.springproject") @PropertySource("classpath:app.properties") public class AppConfig { @Value("${db.driverClassName}") private String driverClassName; @Value("${db.url}") private String url; @Value("${db.username}") private String userName; @Value("${db.password}") private String pwd; @Bean public DataSource dataSource() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(driverClassName); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(pwd); return ds; } }
请注意,PropertySourcesPlaceholderConfigurer类用于根据当前的Spring Environment解析@Value注释中的$ {…}占位符。
使用以下类运行示例
public class App { public static void main( String[] args ){ //EntityManager AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); DriverManagerDataSource dataSource = context.getBean("dataSource", DriverManagerDataSource.class); System.out.println("Driver class name- " + dataSource.getUsername()); context.close(); } }
输出:
Driver class name- user
@PropertySource与环境一起读取属性值
@PropertySource注释为Spring的环境添加了一个PropertySource,因此使用Environment的getProperty()方法是一种读取属性的便捷方法,而不是使用@Value注释。
@Configuration @ComponentScan(basePackages = "com.theitroad.springproject") @PropertySource("classpath:app.properties") public class AppConfig { @Autowired private Environment env; @Bean public DataSource dataSource() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(env.getProperty("db.driverClassName")); ds.setUrl(env.getProperty("db.url")); ds.setUsername(env.getProperty("db.username")); ds.setPassword(env.getProperty("db.password")); return ds; } }
注意如何注入org.springframework.core.env.Environment,并且该对象用于获取属性。
Spring @PropertySource功能
- @PropertySource资源位置中存在的任何$ {...}占位符都是根据已经针对环境注册的一组属性源来解析的。例如
@Configuration @PropertySource("classpath:${app.path:default/path}/app.properties") public class AppConfig { .... .... }
如果app.path存在于已注册的属性源之一(例如,系统属性或者环境变量)中,则占位符将解析为相应的值。如果不是,则将default / path用作默认值。如果未指定默认值且无法解析属性,则抛出IllegalArgumentException。设置为系统属性-System.setProperty(" app.path"," config");
- 根据Java 8约定,@PropertySource注释是可重复的。所有此类@PropertySource注释都需要在同一级别声明。
@Configuration @ComponentScan(basePackages = "com.theitroad.springproject") @PropertySource("classpath:app.properties") @PropertySource("classpath:global.properties") public class AppConfig { .. .. }
我们还可以使用@PropertySources容器注释来聚合几个PropertySource注释。
@Configuration @PropertySources({ @PropertySource("classpath:properties/db.properties"), @PropertySource("classpath:properties/mail.properties") }) public class Configurations { ... ... }
如果找不到值,则忽略异常
如果找不到属性文件或者属性文件中不存在传递的密钥,则默认情况下,Spring框架会引发异常。如果我们拥有一个可能存在或者可能不存在的属性文件,并且不希望引发不存在的异常,则可以将ignoreResourceNotFound属性指定为true。
带有@PropertySource注释
@Configuration @PropertySource(value="classpath:properties/db.properties", ignoreResourceNotFound=true) public class DBConfiguration { }
在XML配置中
<context:property-placeholder location="classpath:config/db.properties" ignore-resource-not-found="false" />
使用XML配置时,如果无法解析占位符,我们还可以指定ignore-unresolvable属性来忽略异常。
<context:property-placeholder location="classpath:config/db.properties" ignore-resource-not-found="false" ignore-unresolvable="false" />
用@PropertySource覆盖属性
如果给定的属性键存在于多个.properties文件中,则最后处理的@PropertySource注释将覆盖此类重复键的值。
例如,给定两个属性文件a.properties和b.properties,请考虑以下两个配置类,它们使用@PropertySource注释来引用它们:
@Configuration @PropertySource("classpath:/com/myco/a.properties") public class ConfigA { } @Configuration @PropertySource("classpath:/com/myco/b.properties") public class ConfigB { }
覆盖顺序取决于在应用程序上下文中注册这些类的顺序。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ConfigA.class); ctx.register(ConfigB.class); ctx.refresh();
在上述情况下,b.properties中的属性将覆盖a.properties中存在的所有重复项,因为ConfigB是最后注册的。