方法1:使用占位符${}
1. 在classpath下新建config.properties
jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///test
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
is.single=abc
2. 在applicationContex.xml中配置
<!--导入资源文件-->
<context:property-placeholder location="classpath:config.properties"/>
3. 之后就可以在xml中以及java代码中使用占位符来获取properties值
xml中
<!--配置C3P0数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
java代码中
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class testPropertyConfig {
@Value("${is.single}")
String test;
@Test
public void test(){
System.out.println(test);
}
}
注意事项:
1. 使用@Value,要依赖于组件扫描和自动装配,所以要启用<context:component-scanbase-package="app" />
2.使用context:property-placeholder,在xml配置中只能出现一次,即所有的配置都应该要配置在一个properties文件中,如果你想把不同的配置放置在不同的properties文件中,那么参考方法2
参考:Could not resolve placeholder in string value
方法2:使用Spring表达式 SpEL
1. 在classpath下新建config.properties
is.single=abc
新建db.properties
jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///test
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
test=def
2. 在applicationContext.xml中配置
<import resource="classpath:applicationContext-db.xml"/>
<!-- 加载properties文件 -->
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
在applicationContext-db.xml中配置
<!--导入资源文件-->
<context:property-placeholder location="classpath:db.properties"/>
3. 之后就可以在xml中以及java代码中来获取不同properties中的值
在applicationContext-db.xml中可以使用占位符
<!--配置C3P0数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
在java代码中,可以使用springExpression Language来指定properties文件来获取,
当然也可以在xml中使用spring Expression Language来获取
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class testPropertyConfig {
@Value("#{configProperties['is.single']}")
String test;
@Value("${test}")
String test02;
@Test
public void test(){
System.out.println(test);
System.out.println(test02);
}
}
使用@PropertySource读取外部配置文件中的k/v,保存到运行的环境变量中。加载完外部的配置文件以后使用${}取出配置文件的值
总结
总结来说,context:property-placeholder是使用占位符来获取properties的值,只能配置一次。
而配置org.springframework.beans.factory.config.PropertiesFactoryBean则可以通过具体bean ID通过spring表达式来获取对应properties中的值
| context:property-placeholder +占位符 | PropertiesFactoryBean +spring表达式 |
配置properties个数 | 1个 | 多个 |
xml中 | 可以使用 | 可以使用 |
java代码中 @Value | 可以使用 | 可以使用 |
解析原理
那么以上这种解析方式,原理是什么呢?通过《Spring in action》这本书,可知:
原理是声明属性源并通过Spring的Environment来检索属性,以下是一个基本的spring配置类
@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties")
public class EnvironmentConfig {
@Autowired
Environment env;
@Bean
public BlankDisc blankDisc() {
return new BlankDisc(
env.getProperty("disc.title"),
env.getProperty("disc.artist"));
}
}
属性文件会加载到Spring的Environment中,之后可以通过getProperty()检索属性。
方法3:自定义属性解析
在使用@Value自动注入的时候,存在一个问题:
即如果我想要为private static字段注入值,如果使用@Value,会报cannot autowired static fields错误。原因是当classloader loads the static values,the spring context还没有加载,所以不能注入。
另一种类似的情况。如果我要在类的静态代码块中使用properties中的值,那么@Value由于是在static静态代码块执行之后,才进行自动注入的,那么如何在静态代码块中使用properties中的值呢?可以使用自定义属性的解析。
通过以上的原理,我们可以自定义类来进行属性解析
1. 在classpath下新建config.properties
is.single=abc
2. 在applicationContext中配置
<!--加载properties文件-->
<!--在Spring中,使用PropertyPlaceholderConfigurer可以在XML配置文件中加入外部属性文件-->
<bean id="propertyConfigurer" class="common.sys.PropertyConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
3. 写PropertyConfigurer类
/**
* Created by Administrator on 2017/10/24.
* PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现
* 也就是BeanFactoryPostProcessor接口的一个实现
* <p>
* PropertyPlaceholderConfigurer可以将上下文(配置文件)中的属性值放在另一个单独的标准java properties文件中去
*/
public class PropertyConfigurer extends PropertyPlaceholderConfigurer {
private static Map<String, Object> ctxPropertiesMap = new HashMap<>();
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws
BeansException {
for (Object key : props.keySet()) {
String keyStr = key.toString();
String value = props.getProperty(keyStr);
ctxPropertiesMap.put(keyStr, value);
}
super.processProperties(beanFactoryToProcess, props);
}
public static String getProperty(String name, String strDefault) {
if (null == ctxPropertiesMap.get(name)) {
return strDefault;
} else {
return (String) ctxPropertiesMap.get(name);
}
}
}
4. 使用,直接通过我们自己写的getProperty()方法来获取
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class testPropertyConfig {
@Test
public void test() {
System.out.println(PropertyConfigurer.getProperty("is.single", null));
}
}
其中PropertyConfigurer类仍然继承了Spring自带的类(底层仍然使用了SpringEnvironment),而更彻底的与spring框架解耦的方式则是自己通过stream来读properties文件
参考:http://blog.youkuaiyun.com/q542928492/article/details/50673038
工具类
public class PropertyUtils {
private static Map map = null;
private static void loadFile() {
map = new HashMap();
try {
Properties p = new Properties();
p.load(PropertyUtils.class.getClassLoader().getResourceAsStream("config.properties"));
Iterator it = p.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
String value = p.getProperty(key);
map.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getValue(String str) {
if (map == null) {
loadFile();
}
return (String) map.get(str);
}
}
使用
String url = PropertyUtils.getValue("is.single");