Spring读取外部属性配置文件的几种方式

本文介绍Spring中PropertyPlaceholderConfigurer的使用方法,包括配置Bean时引入外部配置文件,并展示了不同Spring版本的配置方式。此外,还介绍了几种Java读取properties文件的方法,包括基于ClassLoader、InputStream、ResourceBundle及自定义工具类。
部署运行你感兴趣的模型镜像

本文主要讲述spring如何读取外部配置文件比如properties。

【1】PropertyPlaceholderConfigurer

① 读取方式

在xml配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等),而这些部署细节实际上需要和 Bean 配置相分离。

Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中。

可以在 Bean 配置文件里使用形式为 ${var} 的变量:

  • PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量;

  • Spring 还允许在xml文件中使用 ${propName},以实现属性之间的相互引用。

如这里读取外部的jdbc.properties。

Spring2.0的配置方式

<bean id="propertyConfigurer"
	class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<!--这个是为了防止中文乱码-->
	<property name="fileEncoding" value="UTF-8"/>
	<property name="locations">
		<!--use list to get more inf-->
		<list>
			<value>classpath:jdbc.properties</value>
		</list>
	</property>
</bean>

Spring2.5以后的简写配置方式

<context:property-placeholder location="classpath:jdbc.properties"/>

PropertyPlaceholderConfigurer

该类最终父类为PropertiesLoaderSupport,主要属性如下所示:

public abstract class PropertiesLoaderSupport {

	/** Logger available to subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	protected Properties[] localProperties;

	protected boolean localOverride = false;

	private Resource[] locations;

	private boolean ignoreResourceNotFound = false;

	private String fileEncoding;

	private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
	//...
}

支持使用${propertyName}引用properties等配置文件中的属性

<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  >
	<property name="user" value="${user}"></property>
	<property name="password" value="${password}"></property>
	<property name="jdbcUrl" value="${jdbcUrl}"></property>
	<property name="driverClass" value="${driverClass}"></property>
</bean>

Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用。


【2】Java读取properties文件

① 基于ClassLoder读取配置文件

注意:该方式只能读取类路径下的配置文件。

Properties properties = new Properties();
// 使用ClassLoader加载properties配置文件生成对应的输入流
InputStream in = PropertiesMain.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 使用properties对象加载输入流
properties.load(in);
//获取key对应的value值
properties.getProperty(String key);

② 基于 InputStream 读取配置文件

该方式的优点在于可以读取任意路径下的配置文件,缺点在于一般你需要指定一个绝对路径。

Properties properties = new Properties();
// 使用InPutStream流读取properties文件
 BufferedReader bufferedReader = new BufferedReader(new FileReader("E:/jdbc.properties"));
 properties.load(bufferedReader);
// 获取key对应的value值
properties.getProperty(String key);

③ 通过 java.util.ResourceBundle 类来读取

通过 ResourceBundle.getBundle() 静态方法来获取(ResourceBundle是一个抽象类),这种方式来获取properties属性文件不需要加.properties后缀名,只需要文件名即可

//假设jdbc.properties在类根路径下-src根目录下
ResourceBundle resource = ResourceBundle.getBundle("jdbc");
String value= resource.getString("key"); 

通过这种方式读取值的时候中文会乱码,解决方案有两种。

  • 手动进行解码编码,如下所示:
new String(rb.getString("kefureply_festival").getBytes("ISO-8859-1"),"GBK")
  • properties中的中文进行Unicode转码,如下所示:
a=/u7535/u89c6/u673a

④ 工具类PropertiesUtil

package com.jane.cutover.common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Properties;

/**
 * Created by jianggc at 2022/2/16.
 */
public class PropertiesUtil {

    private static final Logger logger= LoggerFactory.getLogger(PropertiesUtil.class);

    /**
     * 根据文件完整路径,从XXX.properties中读取某个key
     * @param filePath
     * @param key
     * @return
     */
    public static String readWholePath(String filePath,String key){
        try {
            Properties properties = new Properties();
            // 使用InPutStream流读取properties文件
            BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
            properties.load(bufferedReader);
            // 获取key对应的value值
            return properties.getProperty( key);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * 根据文件输入流,读取某个key
     * @param inputStream
     * @param key
     * @return
     */
    public static String readByInputStream(InputStream inputStream, String key){
        try {
            Properties properties = new Properties();
            // 使用InPutStream流读取properties文件
            InputStreamReader streamReader = new InputStreamReader(inputStream,"UTF-8");
            BufferedReader bufferedReader = new BufferedReader(streamReader);
            properties.load(bufferedReader);
            // 获取key对应的value值
            return properties.getProperty( key);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * 读取classpath下的某个XXXX.properties的某个key
     * @param fileName application.properties
     * @param key
     * @return
     */
    public static String readClassPathFile(String fileName, String key){
        try {
            Properties properties = new Properties();
            // 使用InPutStream流读取properties文件
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            InputStreamReader streamReader = new InputStreamReader(inputStream,"UTF-8");
            BufferedReader bufferedReader = new BufferedReader(streamReader);
            properties.load(bufferedReader);
            // 获取key对应的value值
            return properties.getProperty( key);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
        }
        return null;
    }

    public static void main(String[] args){

        InputStream stream =Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties");
        String byInputStream = readByInputStream(stream, "com.jane.file");
        System.out.println("stream---com.jane.file--"+byInputStream);

        String readClassPathFile = readClassPathFile("application.properties", "com.jane.file");
        System.out.println("application.properties---readClassPathFile--"+byInputStream);
    }

}

参考博文:项目不同位置文件读取

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### Spring Boot 读取配置文件方式总结 #### 方法一:`@Value` 注解 通过 `@Value` 注解可以方便地注入单个属性到类的字段中。这种方式适用于简单场景,尤其是只需要获取少量配置项的情况。例如,在 `application.properties` 或 `application.yml` 中定义如下配置: ```properties my.property=Hello, Spring Boot! ``` 或者使用 YAML 格式: ```yaml my: property: Hello, Spring Boot! ``` 可以在 Java 类中这样读取该配置: ```java @Component public class MyConfig { @Value("${my.property}") private String myProperty; public void printProperty() { System.out.println(myProperty); } } ``` 这种方法的优点在于实现简单,缺点是不支持复杂的数据结构绑定[^2]。 --- #### 方法二:`@ConfigurationProperties` 注解 当需要处理一组具有相同前缀的配置时,推荐使用 `@ConfigurationProperties` 注解。它允许将多个相关联的配置映射到一个 POJO 对象上。例如,假设存在以下配置: ```yaml my: app: name: MyApp version: 1.0.0 list: - item1 - item2 ``` 可以通过创建对应的实体类来绑定这些配置: ```java @ConfigurationProperties(prefix = "my.app") @Data // Lombok 自动生成 getter 和 setter public class AppConfig { private String name; private String version; private List<String> list; } ``` 接着将其注册为 Bean 并启用配置加载功能: ```java @Configuration @EnableConfigurationProperties(AppConfig.class) public class Configurer {} ``` 此方法的优势是可以轻松管理复杂的嵌套数据结构并提供类型安全的支持[^1]。 --- #### 方法三:`Environment` 接口 Spring 的 `Environment` 接口提供了另一种灵活的方式来访问应用上下文中所有的属性值。无论是在开发阶段还是生产环境中都可以利用这一机制动态调整行为逻辑。比如要获取某个特定键对应的内容可以直接调用其相应的方法: ```java @Autowired private Environment environment; public void printProperty() { String value = environment.getProperty("my.property"); System.out.println(value); } ``` 相比其他两种方式而言,虽然灵活性更高但也稍微显得不够直观简洁一些。 --- #### 方法四:`@PropertySource` 自定义资源位置 如果项目中有额外的需求需要用到外部自定义 `.properties` 文件而不是默认路径下提供的那些,则可通过声明 `@PropertySource` 来引入新的资源配置源。注意此时还需要配合 `@ComponentScan` 扫描包以及确保正确设置编码格式防止乱码等问题发生。 假设有这样一个名为 `custom-config.properties` 的文件位于项目的根目录之外的地方,并且里面包含了这样的条目: ```properties external.config=value-from-external-source ``` 那么我们就可以按照下面的样子编写代码去加载这个特殊的配置文档了: ```java @Configuration @PropertySource("file:/path/to/custom-config.properties") public class ExternalConfig { @Autowired private Environment env; public void displayExternalConfig() { System.out.println(env.getProperty("external.config")); } } ``` 这里需要注意的是,对于相对路径来说可能需要考虑不同操作系统之间的差异性;而对于绝对路径则可能会带来部署上的不便之处[^3]。 --- ### 总结表格对比 | **特性/方法** | **@Value** | **@ConfigurationProperties** | **Environment** | **@PropertySource** | |-----------------------|--------------------------|----------------------------------|---------------------------|------------------------------| | **适用范围** | 单独属性 | 复杂对象 | 动态运行期 | 非标准位置 | | **优点** | 实现简单 | 支持复杂数据 | 灵活 | 可导入外部文件 | | **局限性** | 不支持复杂结构 | 需要显式开启 | 较繁琐 | 路径依赖可能导致移植困难 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值