在项目中有些参数经常需要修改,或者后期可能会有改动时,那我们最好把这些参数放到properties文件中,在源代码中读取properties里面的配置,这样后期只需要改动properties文件即可,不需要修改源码。
一、java加载配置文件
package readProperties;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
//import org.springframework.core.io.support.PropertiesLoaderUtils;
public class TestProperties {
/**
* @Description: 输出所有配置信息
*/
private static void printAllProperty(Properties props) {
@SuppressWarnings("rawtypes")
Enumeration en = props.propertyNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = props.getProperty(key);
System.out.println(key + " : " + value);
}
}
/**
* 根据key读取value
*
* @Description: 第二种方式:使用缓冲输入流读取配置文件,然后将其加载,再按需操作
* 绝对路径或相对路径, 如果是相对路径,则从当前项目下的目录开始计算,
* 如:当前项目路径/config/config2.properties,
* 相对路径就是config/config2.properties
*/
public static String getProperties_2(String filePath, String keyWord) {
Properties prop = new Properties();
String value = null;
try {
// 通过输入缓冲流进行读取配置文件
InputStream InputStream = new BufferedInputStream(new FileInputStream(new File(filePath)));
// 加载输入流
prop.load(InputStream);
// 根据关键字获取value值
value = prop.getProperty(keyWord);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
/**
* 读取配置文件所有信息
*
* @Description: 第二种方式:使用缓冲输入流读取配置文件,然后将其加载,再按需操作
* 绝对路径或相对路径, 如果是相对路径,则从当前项目下的目录开始计算,
* 如:当前项目路径/config/config2.properties,
* 相对路径就是config/config2.properties
*/
public static void getProperties_2(String filePath) {
Properties prop = new Properties();
try {
// 通过输入缓冲流进行读取配置文件
InputStream InputStream = new BufferedInputStream(new FileInputStream(new File(filePath)));
// 加载输入流
prop.load(InputStream);
printAllProperty(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据key读取value
*
* @Description: 第三种方式:
* 相对路径, properties文件需在classpath目录下,
* 比如:config.properties在包com.test.config下,
* 路径就是/com/test/config/config2.properties
*/
public static String getProperties_3(String filePath, String keyWord) {
Properties prop = new Properties();
String value = null;
try {
//D:\project\java\config\config2.properties
InputStream inputStream = TestProperties.class.getClassLoader().getResourceAsStream(filePath);
prop.load(inputStream);
value = prop.getProperty(keyWord);
} catch (IOException e) {
e.printStackTrace();
}
return value;
}
/**
* 读取配置文件所有信息
*
* @Description: 第三种方式:
* 相对路径, properties文件需在classpath目录下,
* 比如:config.properties在包com.test.config下,
* 路径就是/com/test/config/config2.properties
*/
public static void getProperties_3(String filePath) {
Properties prop = new Properties();
try {
InputStream inputStream = TestProperties.class.getResourceAsStream(filePath);
prop.load(inputStream);
printAllProperty(prop);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 注意路径问题
String properties_2 = getProperties_2("config/config.properties", "jdbc.url");
System.out.println("jdbc.url = " + properties_2);
getProperties_2("config/config.properties");
System.out.println("*********************************************");
// 注意路径问题
String properties_3 = getProperties_3("config/config2.properties", "username");
System.out.println("username = " + properties_3);
getProperties_3("/config/config2.properties");
}
}
props.load(new FileInputStream("db.properties")); 是读取当前目录的db.properties文件
getClass.getResourceAsStream("db.properties"); 是读取当前类所在位置一起的db.properties文件
getClass.getResourceAsStream("/db.properties"); 是读取ClassPath的根的db.properties文件,注意ClassPath如果是多个路径或者jar文件的,只要在任意一个路径目录下或者jar文件里的根下都可以,如果存在于多个路径下的话,按照ClassPath中的先后顺序,使用先找到的,其余忽略.
读取服务器路径文件这种方式:
package com.readProperties;
import org.apache.log4j.Logger;
import java.io.*;
import java.util.Properties;
public class SysConfig {
private static Logger logger = Logger.getLogger(SysConfig.class);
private static SysConfig instance;
//系统配置文件的路径
public static final String SYSCONFIG_PATH = "sysConfig.properties";
public static final String USER_NAME = "username";
public static final String PASS_WORD = "password";
private String userName;
private String passWord;
public String getUserName() {
return userName;
}
public String getPassWord() {
return passWord;
}
public static synchronized SysConfig getInstance() {
if (instance == null) {
try {
instance = new SysConfig();
} catch (IOException e) {
e.printStackTrace();
}
}
return instance;
}
public SysConfig() throws IOException {
Properties properties = SysConfig.getSystemConfigProperties(SYSCONFIG_PATH);
userName = properties.getProperty(USER_NAME);
passWord = properties.getProperty(PASS_WORD);
}
public synchronized static Properties getSystemConfigProperties(String path) {
Properties prop = new Properties();
try (InputStream inputStream = SysConfig.class.getClassLoader().getResourceAsStream(path);) {
prop.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
logger.error("读取配置文件失败", e);
return null;
}
// value = prop.getProperty(keyWord);
logger.info("读取配置文件成功");
return prop;
}
}
二、spring加载配置文件
下面讨论spring两种加载方式,基于xml和基于注解的加载方式。
1. 通过xml方式加载properties文件
以Spring实例化dataSource为例,先在工程目录的src下新建一个conn.properties文件,里面写上上面dataSource的配置:
以Spring实例化dataSource为例,先在工程目录的src下新建一个conn.properties文件,里面写上上面dataSource的配置:
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/shop
username=root
password=root
引入外部文件 :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<!-- PropertyPlaceholderConfigurer类中有个locations属性,接收的是一个数组,即我们可以在下面配好多个properties文件 -->
<list>
<value>classpath*:*conf.properties</value>
<value>classpath.*.properties</value>
</list>
</property>
</bean>
引入外部文件后,就可以在xml中用${key}替换指定的properties文件中的值,通常项目中都会将jdbc的配置放在properties文件中
然后在只需要在beans.xml中做如下修改即可:
<!-- 这些配置Spring在启动时会去conn.properties中找 -->
<bean id="dataSource" class="${dataSource}">
<!--<bean id="dataSource" class="cn.com.cpic.demo"-->
<property name="driverClass" value="${driverClass}" />
<property name="jdbcUrl" value="${jdbcUrl}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
</bean>
通过demo就可以获取配置文件的username和password的值了
public class demo {
String username;
String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
为简化PropertyPlaceholderConfigurer的使用,Spring提供了<context:property-placeholder/>
元素,启用它后,开发者便不用配置PropertyPlaceholderConfigurer对象了
配置属性文件
<!-- 数据库配置文件位置 -->
<context:property-placeholder location="classpath:jdbc.properties" />
2) 注意点:踩过的坑
在Spring中的xml中使用<context:property-placeholderlocation>标签导入配置文件时,想要导入多个properties配置文件,如下:
<context:property-placeholderlocation="classpath:db.properties " />
<context:property-placeholderlocation="classpath:zxg.properties " />
结果发现不行,第二个配置文件始终读取不到,Spring容器是采用反射扫描的发现机制,通过标签的命名空间实例化实例,当Spring探测到容器中有一个org.springframework.beans.factory.config.PropertyPlaceholderConfigurer的Bean就会停止对剩余PropertyPlaceholderConfigurer的扫描,即只能存在一个实例
如果有多个配置文件可以使用 “,” 分隔
<context:property-placeholderlocation="classpath:db.properties,classpath:monitor.properties" />
可以使用通配符 *
<context:property-placeholderlocation="classpath:*.properties" />
2. 通过注解方式加载properties文件
第一种配置方式:
<!-- 确保可在@Value中, 使用SeEL表达式获取资源属性 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="configProperties" />
</bean>
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:config/*.properties</value>
</list>
</property>
</bean>
在java代码中用@Value获取配置属性值
@Value("${shop.url}")
private String url;
还有一种方式更简洁:
<bean id="prop" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="fileEncoding" value="UTF-8"/>
<property name="locations"><!-- 这里是PropertiesFactoryBean类,它也有个locations属性,也是接收一个数组,跟上面一样 -->
<array>
<value>classpath:public.properties</value>
</array>
</property>
</bean>
<!--或者-->
<context:property-placeholder location="classpath:**.properties" />
//注意,这种表达式要有set方法才能被注入进来,注解写在set方法上即可
private String url;
@Value("#{prop.shop.url}")
//@Value表示去beans.xml文件中找id="prop"的bean,它是通过注解的方式读取properties配置文件的,然后去相应的配置文件中读取key=shop.url的对应的value值
public void setUrl(String url) {
this.token= url;
}
3.通过 @PropertySource和@Value 来读取配置文件
举个栗子:
@Component
//@PropertySource注解用来指定要读取的配置文件的路径从而读取这些配置文件,可以同时指定多个配置文件;
@PropertySource(value = {"classpath:common.properties", "classpath:abc.properties"})
public class Configs {
//@Value("${connect.api.apiKeyId}")用来读取属性key=connect.api.apiKeyId所对应的值并把值赋值给属性apiKeyId;
@Value("${connect.api.apiKeyId}")
public String apiKeyId;
@Value("${connect.api.secretApiKey}")
public String secretApiKey;
public String getApiKeyId() {
return apiKeyId;
}
public String getSecretApiKey() {
return secretApiKey;
}
}
4.自定义 PropertyPlaceholderConfigurer