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;
    }
}

关键点解析:

  1. 每个Class对象都持有实例化它的ClassLoader引用
  2. ClassLoader不仅用于加载类,也可用于加载资源文件
  3. getResourceAsStream会在类路径中查找resourceFileName文件
  4. 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仓库,包含完整实现细节。


原始标题:How to Inject a Property Value Into a Class Not Managed by Spring?