1. 概述
Spring框架中,被@Repository
、@Service
、@Controller
等注解标记的类由容器直接管理,注入配置属性非常简单。但向非Spring管理的类传递配置就没那么直观了。
常见的解决方案有两种:
- 使用Java的
ClassLoader
加载配置文件 - 在Spring管理的Bean中手动实例化目标类并设置参数(推荐方案,因为配置不必强制存放在
*.properties
文件中)
本文将重点探讨如何通过ClassLoader
加载*.properties
文件,以及如何将Spring已加载的配置注入非托管类。
2. 使用ClassLoader加载配置
*.properties
文件本质是存储配置信息的资源文件。除了依赖Spring等框架的自动配置机制,我们也可以直接用Java的ClassLoader
实现类似功能。
下面创建一个配置容器类PropertiesLoader
,通过loadProperties
方法加载指定资源文件:
public class PropertiesLoader {
public static Properties loadProperties(String resourceFileName) throws IOException {
Properties configuration = new Properties();
InputStream inputStream = PropertiesLoader.class
.getClassLoader()
.getResourceAsStream(resourceFileName);
configuration.load(inputStream);
inputStream.close();
return configuration;
}
}
关键点解析:
- 每个
Class
对象都持有实例化它的ClassLoader
引用 ClassLoader
不仅用于加载类,也可用于加载资源文件getResourceAsStream
会在类路径中查找resourceFileName
文件load(InputStream)
方法解析*.properties
文件,支持以下语法:- 分隔符:
=
或:
- 注释标记:行首的
#
或!
- 分隔符:
获取配置值时直接调用:
String property = configuration.getProperty(key);
⚠️ 注意:此方案需要手动处理资源流关闭和异常,属于基础Java操作,有经验的开发者应该很熟悉。
3. 通过Spring加载配置
更优雅的方案是利用Spring的配置管理能力。创建一个初始化器Bean,由Spring注入配置值后,再由它实例化目标类:
@Component
public class Initializer {
private final String someInitialValue;
private final String anotherManagedValue;
public Initializer(
@Value("someInitialValue") String someInitialValue,
@Value("anotherValue") String anotherManagedValue) {
this.someInitialValue = someInitialValue;
this.anotherManagedValue = anotherManagedValue;
}
public ClassNotManagedBySpring initClass() {
return new ClassNotManagedBySpring(
this.someInitialValue, this.anotherManagedValue);
}
}
使用方式:
ClassNotManagedBySpring classNotManagedBySpring = initializer.initClass();
✅ 优势:
- 配置值由Spring统一管理,支持环境隔离
- 避免手动处理资源流和异常
- 与Spring生态无缝集成(如
@ConfigurationProperties
)
❌ 局限:
- 需要额外创建初始化器类
- 目标类实例化时机受Spring生命周期控制
4. 总结
两种方案对比:
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
ClassLoader加载 | 纯Java环境/轻量级配置 | 无Spring依赖 | 需手动管理资源/异常处理 |
Spring初始化器 | Spring项目/复杂配置需求 | 配置管理统一/支持环境隔离 | 增加初始化器类/生命周期耦合 |
对于Spring项目,强烈推荐使用初始化器方案——它简单粗暴地解决了配置注入问题,同时保持了代码的整洁性。纯Java环境下,ClassLoader方案则是轻量级的选择。
示例代码已托管至GitHub仓库,包含完整实现细节。