Recently , in the process of project development, I encountered the need to define some custom variables in the properties file for the java program to dynamically read and modify the variables, and no longer need to modify the code. I took this opportunity to sort out and analyze the method of reading the properties file content through the java program in the project integrated and developed by Spring+SpringMVC+Mybatis, and share it with you first.
2. Introduction to the project environment
Spring 4.2.6.RELEASE SpringMvc
4.2.6.RELEASE
Mybatis 3.2.8
Maven 3.3.9
Jdk 1.7
Idea 15.04 content in
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
The above configuration is equivalent to the following configuration, which is a simplification of the following configuration
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
Note: In this way, if you are in spring-mvc If there is the following configuration in the .xml file, the following red part must not be missing. For its function and principle, see another blog: The function and principle analysis of the use-default-filters attribute of the context:component-scan tag
<!-- Configure component scanning, only Controller annotations are scanned in the springmvc container--> <context:component-scan base-package="com.hafiz.www" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
Method 2. Use annotation injection, mainly used in java code to use annotation to inject the corresponding value value in the properties file
<bean id="prop" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <!-- Here is the PropertiesFactoryBean class, which also has a locations property and also receives an array, the same as above --> <property name="locations"> <array> <value>classpath:jdbc.properties</value> </array> </property> </bean>
Method 3. Use the util:properties tag to expose the content in the properties file
<util:properties id="propertiesReader" location="classpath:jdbc.properties"/>
Note: To use the above line configuration, you need to configure it in spring-dao.xml The header of the file declares the following red section
<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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework. org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework. org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">Method
4. Expose properties to custom sub when loading context through PropertyPlaceholderConfigurer Properties of the class for use in the program
<bean id="propertyConfigurer" class="com.hafiz.www.util.PropertyConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="ignoreResourceNotFound " value="true"/>
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
The declaration of the custom class PropertyConfigurer is as follows :
package com.hafiz.www.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import java.util.Properties;
/**
* Desc:properties配置文件读取类
* Created by hafiz.zhang on 2016/9/14.
*/
public class PropertyConfigurer extends PropertyPlaceholderConfigurer {
private Properties props; // 存取properties配置文件key-value结果
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException {
super.processProperties(beanFactoryToProcess, props);
this.props = props;
}
public String getProperty(String key){
return this.props.getProperty(key);
}
public String getProperty(String key, String defaultValue) {
return this.props.getProperty(key, defaultValue);
}
public Object setProperty(String key, String value) {
return this.props.setProperty(key, value);
}
}
How to use: Use @Autowired annotation to inject in the class to be used.
Method 5. Customize the tool class PropertyUtil, and read the properties file content in the static static code block of this class and save it in the static property for other programs to use
package com.hafiz.www.util;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Properties;
/**
* Desc:properties file get tool class
* Created by hafiz.zhang on 2016/9/15.
*/
public class PropertyUtil {
private static final Logger logger = LoggerFactory.getLogger(PropertyUtil.class );
private static Properties props;
static{
loadProps();
}
synchronized static private void loadProps(){
logger.info("Start loading properties file content....");
props = new Properties();
InputStream in = null;
try {
<!--The first one, get the properties file stream through the class loader-->
in = PropertyUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
<!--Second, get properties file stream through class-->
//in = PropertyUtil.class.getResourceAsStream("/jdbc.properties");
props.load(in);
} catch (FileNotFoundException e) {
logger.error("jdbc.properties file not found");
} catch (IOException e) {
logger.error("IOException occurred");
} finally {
try {
if(null != in) {
in.close();
}
} catch (IOException e) {
logger.error("jdbc.properties file stream closed exception");
}
}
logger.info("Loading properties file content completed..... ......");
logger.info("properties file content: " + props);
}
public static String getProperty(String key){
if(null == props) {
loadProps();
}
return props.getProperty(key);
}
public static String getProperty (String key, String defaultValue) {
if(null == props) {
loadProps();
}
return props.getProperty(key, defaultValue);
}
}
Explanation: In this way, when the class is loaded, it will automatically Read the content of the configuration file at the specified location and save it to a static property, which is efficient and convenient, loaded once, and can be used multiple times.
Fourth, matters needing attention and suggestions
The above five methods, the first three methods are relatively rigid, and if you want to use it in a bean annotated with @Controller, you need to declare it in the SpringMVC configuration file spring-mvc.xml. To use it in non-@Controller-annotated beans such as Service and @Respository, you need to declare it in spring.xml in the Spring configuration file. For the reason, please refer to another blog: A first look at the relationship between Spring and SpringMVC parent-child container
I personally recommend the fourth and fifth configuration methods, the fifth is the best, it does not even need to inject tool class objects, directly call static The method is obtained, and it is only loaded once, and the efficiency is also high. Moreover, the first three methods are not very flexible, and the key value of @Value needs to be modified.
Five, test to verify whether it is available
1. First we create PropertiesService
package com.hafiz.www.service;
/**
* Desc:java program to obtain the service of properties file content
* Created by hafiz.zhang on 2016/9/16.
*/
public interface PropertiesService {
/**
* The first implementation method gets the value of the specified key in the properties file
*
* @return
*/
String getProperyByFirstWay();
/**
* The second implementation method gets the value of the specified key in the properties file
*
* @return
*/
String getProperyBySecondWay();
/**
* The third implementation method gets the value of the specified key in the properties file
*
* @return
* /
String getProperyByThirdWay();
/**
* The fourth implementation method gets the value of the specified key in the properties file
*
* @param key
*
* @return
*/
String getProperyByFourthWay(String key);
/**
* The fourth implementation method Get the value of the specified key in the properties file
*
* @param key
*
* @param defaultValue
*
* @return
*/
String getProperyByFourthWay(String key, String defaultValue);
/**
* The fifth implementation method gets the value of the specified key in the properties file
*
* @param key
*
* @return
*/
String getProperyByFifthWay(String key) ;
/**
* The fifth implementation method gets the value of the specified key in the properties file
*
* @param key
*
* @param defaultValue
*
* @return
*/
String getProperyByFifthWay(String key, String defaultValue);
}
2. Create an implementation class PropertiesServiceImpl
package com.hafiz.www.service.impl;
import com.hafiz.www.service.PropertiesService;
import com.hafiz.www.util.PropertyConfigurer;
import com.hafiz.www.util.PropertyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* Desc:java程序获取properties文件内容的service的实现类
* Created by hafiz.zhang on 2016/9/16.
*/
@Service
public class PropertiesServiceImpl implements PropertiesService {
@Value("${test}")
private String testDataByFirst;
@Value("#{prop.test}")
private String testDataBySecond;
@Value("#{propertiesReader[test]}")
private String testDataByThird;
@Autowired
private PropertyConfigurer pc;
@Override
public String getProperyByFirstWay() {
return testDataByFirst;
}
@Override
public String getProperyBySecondWay() {
return testDataBySecond;
}
@Override
public String getProperyByThirdWay() {
return testDataByThird;
}
@Override
public String getProperyByFourthWay(String key) {
return pc.getProperty(key);
}
@Override
public String getProperyByFourthWay(String key, String defaultValue) {
return pc.getProperty(key, defaultValue);
}
@Override
public String getProperyByFifthWay(String key) {
return PropertyUtil.getPropery(key);
}
@Override
public String getProperyByFifthWay(String key, String defaultValue) {
return PropertyUtil.getProperty(key, defaultValue);
}
}
3.控制器类PropertyController
package com.hafiz.www.controller;
import com.hafiz.www.service.PropertiesService;
import com.hafiz.www.util.PropertyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Desc:properties测试控制器
* Created by hafiz.zhang on 2016/9/16.
*/
@Controller
@RequestMapping("/prop")
public class PropertyController {
@Autowired
private PropertiesService ps;
@RequestMapping(value = "/way/first", method = RequestMethod.GET)
@ResponseBody
public String getPropertyByFirstWay(){
return ps.getProperyByFirstWay();
}
@RequestMapping(value = "/way/second", method = RequestMethod.GET)
@ResponseBody
public String getPropertyBySecondWay(){
return ps.getProperyBySecondWay();
}
@RequestMapping(value = "/way/third", method = RequestMethod.GET)
@ResponseBody
public String getPropertyByThirdWay(){
return ps.getProperyByThirdWay();
}
@RequestMapping(value = "/way/fourth/{key}", method = RequestMethod.GET)
@ResponseBody
public String getPropertyByFourthWay(@PathVariable("key") String key){
return ps.getProperyByFourthWay(key, "defaultValue");
}
@RequestMapping(value = "/way/fifth/{key}", method = RequestMethod.GET)
@ResponseBody
public String getPropertyByFifthWay(@PathVariable("key") String key){
return PropertyUtil.getProperty(key, "defaultValue");
}
}
4.jdbc.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.196:3306/dev?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
jdbc.maxActive=200
jdbc.minIdle=5
jdbc.initialSize=1
jdbc.maxWait=60000
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.minEvictableIdleTimeMillis=300000
jdbc.validationQuery=select 1 from t_user
jdbc.testWhileIdle=true
jdbc.testOnReturn=false
jdbc.poolPreparedStatements=true jdbc.maxPoolPreparedStatementPerConnectionSize
=20
jdbc.
data
test=com.hafiz.www
6. Summary
Through this combing and test, we understand the parent-child container relationship between Spring and SpringMVC and the use-default-filters attribute that is most easily ignored when the context:component-scan tag package is scanned. function and principle. Can better locate and quickly solve the problems encountered again. All in all, great~~