本文属性文件的读取主要针对于传统spring框架的项目。
主要介绍以下三种方式:
[1] 通过 spring 支持的 xml 标签,加载属性文件;
[2] 通过 spring 注解获取属性值;
[3] 通过字节流读取,按规则存储在容器类中。
方式一、在 xml 标签中指定属性文件位置
class="xml" name="code">
<!-- 可以通过 * 通配符方式加载多个属性文件 -->
<context:property-placeholder location="classpath:config.properties"/>
config.properties 文件位于 src/main/resources 下,其内容如下:
#jdbc config
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/demo
jdbc.username=mysql
jdbc.password=password
配置数据源:
<bean id = "dataSource" class = "org.springframework.jdbc.dataSource.DriverManagerDataSource">
<!-- 使用 ${} 进行取值,它属于 SpEL 表达式 -->
<property name = "driverClassName" value = "${jdbc.driver}"/>
<property name = "url" value = "${jdbc.url}"/>
<property name = "username" value = "${jdbc.username}"/>
<property name = "password" value = "${jdbc.password}"/>
</bean>
测试类:
// import ...
/**
* 通过 xml 标签方式加载属性文件测试类
*/
public class TagLoadTest {
@Test
public void configReadTest() {
// root-context.xml是spring的根配置文件,与config.properties同级目录
ApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
DriverManagerDataSource dataSource = (DriverManagerDataSource) context.getBean("dataSource");
System.out.printf("dataSource username is %s \n", dataSource.getUsername()");
}
}
输出结果为:
dataSource username is mysql // 成功读取到 username 对应的值为 mysql
方式一的另一种写法:不使用标签,而是使用spring提供的PropertyPlaceholderConfigurer。
如下:
<bean id = "propertyConfigurer" class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name = "location" value = "config.properties"/>
<!-- 加载多个文件,使用name = "locations" -->
<!--
<property name = "locations">
<array>
<value>config.properties</value>
</array>
</property>
-->
</bean>
方式二、使用注解方式读取属性文件的值
在使用注解前,首先要告诉spring属性文件的位置:
<!-- 开启包扫描 -->
<context:component-scan base-package="com.xxx"/>
<!-- 定义属性文件类 -->
<bean id = "propertyConfigurer" class = "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name = "location" value = "config.properties"/>
</bean>
随意定义一个被spring管理的bean:
@Component("test0")
public class ForAnnotationTest {
private String username;
@Value("${jdbc.username}")// 可以直接注解在username字段上,在这主要表明spring通过set方法赋值
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");
ForAnnotationTest annotationTest = (ForAnnotationTest) context.getBean("test0");
System.out.println("username is : " + annotationTest.getUsername());
输出:
username is : mysql
方式二有另一种写法,不过稍有不同:使用${}取值可以取得属性文件中带“.”号的键所对应的值,如“jdbc.username=mysql",而使用#{}取值时,若键中带有“.”号,则会提示
异常。
该写法如下:
(先将config.properties中的jdbc.username改为username)
<!-- 首先将PropertyPlaceholderConfigurer改为PropertiesFactoryBean -->
<bean id = "configBean" class = "org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name = "location" value = "classpath:config.properties">
</bean>
// 修改ForAnnotationTest类中注解的取值方式
@Value("#{configBean.username}")
public void setUsername(String username) {
this.username = username;
}
如果必须要用#{}取值方式获取带有“.”键的值(基本上不会有这种要求),可以通过#{'${}'}嵌套使用,如
@Value("#{'${jdbc.username}'}")
,但前提是需要在xml中同时配置这两种取值方式的属性文件配置(上文中的两个propertyConfigurer类)。显而易见地,这种情况下使用#{}取值是不可取的。#{}方式强大在于它的运算能力,包括获取对象属性值、数值运算等。
方式三、通过Properties类和IO流,将属性文件读取到键值对的容器中,使用时直接通过键获取
1. 为了让属性文件的路径可配置,可将文件路径字符串作为一个bean,通过spring获取:
<bean id = "configPath" class = "java.lang.String">
<constructor-arg>
<!-- linux 下,以tomcat目录为相对路径的写法 -->
<value>file:webapps-conf/xx/xxx.properties</value>
</constructor-arg>
</bean>
注意:使用tomcat容器启动时,相对路径为tomcat下的bin目录; 直接调用
JVM而非使用WEB容器启动时(单元测试就是其中一种),相对路径为项目目录。
2. 获取 spring 中的 bean "configPath",使用IO流创建 Properties类.
package configPack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Properties;
/**
* author: getthrough
* date: 2018/2/28
* description: a class for loading properties files
*/
public class ConfigLoader {
private static Properties properties = new Properties();
private static Logger logger = LoggerFactory.getLogger(ConfigLoader.class);
// @Autowired
// private static configPack.AppContext appContext;// 这里不能用注入的方式
static {
try {
String configPath = getConfigPath();
InputStream is = new FileInputStream(new File(configPath));
properties.load(is);
logger.info("####### properties file has loaded! #######");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getConfigPath() {
String configPath = (String) AppContext.getBean("configPath");
logger.info("configPath:>>>>>>>>>>>>>>>>>>>" + configPath);
if (null != configPath && configPath.startsWith("file:")) {
configPath = configPath.replace("file:", "");
}
if (null != configPath && configPath.startsWith("classpath:"))
configPath = configPath.replace("classpath:", "");
return configPath;
}
public static String getValueByKey(String key) {
return getValueByKey(key, "");
}
public static String getValueByKey(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}
}
其中的 AppContext 类在 配置文件中定义,其类内容如下:
package configPack;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.io.Serializable;
/**
* author: getthrough
* date: 2018/2/28
* description:
*/
//@Service
public class AppContext implements ApplicationContextAware,Serializable {
private static final long serialVersionUID = 4606527550169443963L;
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AppContext.setContext(applicationContext);// 通过 set 方法注入,获取 应用上下文
}
public static <T> T getBean(String beanName) {
if (null == context)
throw new RuntimeException("ApplicationContext has not been injected!");
return (T) context.getBean(beanName);
}
public static <T> T getBean(Class<?> clazz) {
if (null == context)
throw new RuntimeException("ApplicationContext has not been injected!");
return (T) context.getBean(clazz);
}
public static void setContext(ApplicationContext context) {
AppContext.context = context;
}
public static ApplicationContext getContext() {
return context;
}
}
测试:
创建一个随项目启动即创建的
Servlet,或者 创建一个 Listener,在初始化的方法中测试效果(以Listener为例):
package configPack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* author: getthrough
* date: 2018/3/5
* description:
*/
public class TestListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(TestListener.class);
public void contextInitialized(ServletContextEvent sce) {
String valueByKey = ConfigLoader.getValueByKey("jdbc.username");
logger.info("value to \"jdbc.username\" is >>>>>>>>>>>>>>>" + valueByKey);
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
输出结果:
value to "jdbc.username" is >>>>>>>>>>>>>>>root
总结
方式一读取配置文件非常适合在 spring 配置文件中获取指定位置的属性文件内容;
方式二基本属于打酱油;
方式三非常适合在具体代码中获取指定位置属性文件内容,如 ip,端口,ftp 地址等。
方式一和方式二的内容是在公司无法粘贴代码环境下写的,词语拼写很可能出错,请自行分辨!(也因此没有代码文件,如有需要,后期补充)
方式三代码地址: https://github.com/Getthrough/loadConfigFile