在实际开发中,很多时候我们需要在配置文件中配置某些配置,以便在程序中获取。
SpringBoot提供获取配置的方式有:
1.使用注解的方式获取指定配置的值
在bean类中定义属性变量,并在字段上面加上注解@Value("${propertyName}")来获取指定配置的值。
如:
配置文件中:
project.author=shaoyu1
Java代码中:
@Value("${project.author}") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }
2.定义配置类
在系统定义一个类,专门作为配置类,在类上加上注解@ConfigurationProperties(prefix ="指定配置名称前缀")和@Component将之定义为一个bean,其属性名称需要和配置名一一对应。
如:
配置文件中:
my.test1=1111 my.test2=2222 my.test3=3333
Java代码中:
@ConfigurationProperties(prefix ="my") @Component public class ConfigBean { private String test1; private String test2; private String test3; //省略getter,setter
以上两种方法获取配置的方式很唯一,很难变通,一旦我们新增了一个配置,就要重新修改代码,不可拓展。
所以我们需要一些更好的方式来获取配置。
其实在第二种方式中,我们可以稍微修改一下,使用Map作为属性,再在配置文件中以固定的格式编写配置,就可以很顺利的获取固定格式的所有配置信息。
代码如下:
@ConfigurationProperties(prefix ="my") @Component public class ConfigBean { private static Map<String,String> config; private Map<String, String> getConfig() { return config; } public void setConfig(Map<String, String> config) { this.config = config; } public static String getString(String key){ return config.get(key); } }
在配置文件中,我们只需要将所有需要的配置都加上my.config的前缀,那么这个配置类就可以获取所有我们需要的配置信息了。
配置文件如下:
my.config.test1=1111 my.config.test2=2222 my.config.test3=3333
再拓展还可以使用Map<String,Object>来做为属性,只要配置名称能够匹配格式,都是可以获取的。
其实做到这一步还是会觉得很麻烦,还要规定格式之类的,那么还有没有别的方式呢?
当然有。
Spring在加载配置的时候,其实是使用了PropertyPlaceholderConfigurer这个类,这个类是BeanFactoryPostProcessor的子类,其主要的作用是在Spring容器初始化的时候,会读取xml或者annotation对Bean进行初始化。初始化的时候,这个PropertyPlaceholderConfigurer会拦截Bean的初始化,初始化的时候会对配置的${pname}进行替换,根据我们Properties中配置的进行替换。从而实现表达式的替换操作 。比如说我们刚刚提到的第一种方式使用@Value注解,此外,我们在配置文件中也可以使用${pname}进行属性的替换。
在了解了这个类的作用原理之后,我们知道这个类会获取所有的配置信息,所以可以在这个类上面着手,我们翻看源码发现这个类并没有将这些配置信息暴露出来,所以想办法让这些配置信息暴露出来,问题就迎刃而解了。思路如下:
我们写一个类继承PropertyPlaceholderConfigurer,重写processProperties方法,这个方法的第二个参数就是配置信息。在类中新定义一个属性变量,来存储参数的数据,再调用父类的processProperties,在配置文件中自定义这个bean,并指定配置文件,就可以完美获取配置信息了。
代码如下:
/** * @Description: * @Author: shaoyu1 * @Date Create in 2018/6/25 16:17 */ public class PropertiesUtil extends PropertyPlaceholderConfigurer { private static Map<String, Object> contextPropertys; @Override protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { contextPropertys = new HashMap<String, Object>(); for (Object key : props.keySet()) { String keyStr = key.toString(); String value = props.getProperty(keyStr); if (System.getProperties().containsKey(keyStr)) { value = System.getProperty(keyStr); props.setProperty(keyStr, value); } contextPropertys.put(keyStr, value); } super.processProperties(beanFactoryToProcess, props); } public static Object getValue(String name) { return contextPropertys.get(name); } public static Object getValue(String name,Object defaultValue) { Object contextValue=contextPropertys.get(name); return contextValue==null?defaultValue:contextValue; } //show all propertys public static void showProperties() { Set <String> keys = contextPropertys.keySet(); for (String key:keys) { System.out.println(key+"="+contextPropertys.get(key)); } } }
<bean id="propertiesUtil" class="com.yhd.shaoyu.onlineconfig.util.PropertiesUtil"> <property name="locations"> <list> <value>classpath:application.properties</value> </list> </property> <property name="fileEncoding" value="UTF-8"/> </bean>
我们来测试一下:
@RunWith(SpringRunner.class) @SpringBootTest public class StartApplicationTest { @Test public void testConfig(){ System.out.println("配置类:"); System.out.println(ConfigBean.getString("test1")); System.out.println(ConfigBean.getString("test2")); System.out.println(ConfigBean.getString("test3")); System.out.println("\n注解方式:"); ConfigBean2 config2 = BeanUtil.getBean(ConfigBean2.class); System.out.println(JSON.toJSONString(config2)); System.out.println("\n继承PropertyPlaceholderConfigurer类的方式:"); PropertiesUtil.showProperties(); } }
运行结果如下:
配置类: 1111 2222 3333 注解方式: {"name":"shaoyu1"} 继承PropertyPlaceholderConfigurer类的方式: spring.datasource.data=classpath:data.sql spring.thymeleaf.servlet.content-type=text/html logging.config=classpath:logback.xml spring.thymeleaf.mode=HTML5 spring.datasource.password=shaoyu1 spring.jpa.show-sql=true spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.initialization-mode=never spring.datasource.username=shaoyu1 spring.thymeleaf.encoding=UTF-8 spring.datasource.schema=classpath:schema.sql spring.thymeleaf.prefix=classpath:/templates/ spring.datasource.url=jdbc:mysql://localhost:3306/shaoyu1 spring.thymeleaf.suffix=.html server.port=8080 my.test3=3333 my.config.test1=1111 my.test2=2222 my.test1=1111 my.config.test3=3333 project.author=shaoyu1 my.config.test2=2222
第三种方式将配置文件中的所有配置信息都获取到了,我们在开发过程中就可以随便加配置信息啦。