SpringBoot系列之@PropertySource和@Value注解(二)
前言
本文我们来看看在Spring中如何使用@PropertySource和@Value注解从属性文件读取值,同时呢我们也将讨论有关Spring Environment接口的信息以及相应的XML配置。@PropertySource注解主要使用Spring的Environment接口从属性文件中读取,事实上,此注解位于@Configuration类上,而 Spring @Value注解可用于在字段或方法上指定表达式,常见的例子是从.properties文件中指定属性以及默认值,接下来我们一起来看看。
@PropertySource和@Value注解
首先我们在resources文件夹下创建一个名为config.properties的文件,内容如下:
接下来我们在上一节所创建的SpringConfig配置文件中添加一个name字段,如下:
package com.demo.springboot; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource(value = "classpath:config.properties") public class SpringConfig { @Value("${name}") public String name; @Bean public UserDAL getUserDAL() { System.out.println(name); return new UserDAL(); } }
我们通过@PropertySource注解声明配置文件存放的地方,一般来讲如果是内部配置文件约定是放在spring默认为我们创建的resources文件夹下,当然我们也可以在此文件夹下创建目录,同时更改注解存放的地址即可。如果要读取的值存放到内部不同文件夹或者内部和外部,此时我们需要使用@PropertySources,要是读取的多个配置文件中对应的键一样,此时会以最后读取的配置文件中的值进行覆盖,比如如下b配置文件中也存在name,那么配置文件中的值将覆盖a配置文件中的值。
@PropertySources({@PropertySource("classpath:a.properties"),@PropertySource("classpath:b.properties")})
我们通过注解@Value来读取找到的配置文件中的值,其中$符号相信我们都不陌生,起到占位符的作用。此时我们不禁想,要是指定配置文件不存在或者找到的配置文件中的值和声明注解的占位符不匹配会怎样呢?下面我们将我们创建的配置文件中的name修改为如下名称,此时将抛出如下异常:
name11=Jeffcky
同理对于配置文件中未查找到,那更加值也将不存在也会抛出如上异常,由于映射值是交给spring内置在处理,我们可能完全捕捉不到这种异常,所以为了解决映射出现异常情况,我们需要给个默认值,对name字段进行如下修改:
@Value("${name:}") public String name;
在占位符中通过冒号指定若映射值不存则使用上述默认空字符串,很完美的解决了这个问题,此时我们打印出如下空字符串
在开头我们讲解到注解@PropertySource是添加到了Spring Environment接口中,所以我们可以从Spring IOC容器中获取该接口,同样也可以获取上述name值,如下:
package com.demo.springboot; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource(value = "classpath:config.properties") public class SpringConfig {
@Autowired private Environment environment; @Bean public UserDAL getUserDAL() { System.out.println(environment.getProperty("name")); return new UserDAL(); } }
上述我们讲解了映射的占位符不匹配的问题,要是映射的占位符找到了,但是值的类型不匹配该咋办呢?比如如下,将抛出异常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Cannot convert value of type 'java.lang.String' to required type 'com.sun.org.apache.xpath.internal.operations.String'.....
当然上述情况是及其不可能发生的,我是手贱搞了快捷方式看都没看,发现也是字符串怎么会抛出如上异常,搞了一会才发现导入的包搞错了。要是我们将配置文件中name修改为1.0,同时我们将字段name类型修改为int,此时会怎样呢?
Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "1.0"
此时将出现映射类型不匹配的情况,首先确认到底是映射类型是否为int,若是将配置文件中类型修改1,或者进行如下修改:
@Value("#{new Double('${name}')}") public int name;
或者
@Value("#{T(Double).parseDouble('${name}')}") public int name;
否则将字段类型修改为double(当然包装类型也可)。如下:
@Value("${name}") public double name;
如上我们一直讨论的是将配置文件放在spring resources目录下,要是我们现在将上述配置文件放在其他目录(外部目录)呢,比如如下:
org.springframework.beans.factory.BeanDefinitionStoreException:...... class path resource [config.properties] cannot be opened because it does not exist
对于内部目录即放在resources目录下,声明注解@PropertySource时参数使用classpath,而对于外部目录声明注解@PropertySource时参数使用file。如下:
@PropertySource(value = "file:../../config.properties")
此时我们发现同样会抛出异常,只不过内容不一样而已。这是因为无论是将文件放在内外部,路径必须绝对路径而非相对路径,只不过将文件放在内部默认目录是resources而已。
org.springframework.beans.factory.BeanDefinitionStoreException: ....... nested exception is java.io.FileNotFoundException: ..\..\config.properties (系统找不到指定的文件。)
针对Windows系统而言,我们可使用定义环境变量来解决,这里需要注意,定义完环境变量后,此时需要重启idea才能重新加载系统定义的环境变量,否则不生效,如下:
@PropertySource(value = "file:${Test}/config.properties")
总结
本文我们详细讲解了@PropertySource和@Value注解,针对读取外部配置文件其实还有一些细节需要深入,这里并未过多深讨,等待哪天再次有了更多积累会进一步分析,好了,感谢阅读本文的您,我们下节见。