由类型安全配置支持的弹簧环境

我想在我的项目中使用typeafe配置(HOCON配置文件),这有助于轻松和有组织的应用程序配置。目前我正在使用普通的Java属性文件(application.properties),这在大项目上很难处理。

我的项目是Spring MVC(不是Spring Boot项目)。有没有办法支持我的Spring环境(我正在注入到我的服务中)由typeafe配置支持。这不应该阻止我现有的环境用法,如注释等。@Value@Autowired Environment

我怎样才能用最少的工作量和对代码的更改来做到这一点。

这是我目前的解决方案:寻找是否有其他更好的方法

@Configuration
public class PropertyLoader{
    private static Logger logger = LoggerFactory.getLogger(PropertyLoader.class);

    @Bean
    @Autowired
    public static PropertySourcesPlaceholderConfigurer properties(Environment env) {
        PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();

        Config conf = ConfigFactory.load();
        conf.resolve();
        TypesafePropertySource propertySource = new TypesafePropertySource("hoconSource", conf);

        ConfigurableEnvironment environment = (StandardEnvironment)env;
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addLast(propertySource);
        pspc.setPropertySources(propertySources);

        return pspc;
    }
}

class TypesafePropertySource extends PropertySource<Config>{
    public TypesafePropertySource(String name, Config source) {
        super(name, source);
    }

    @Override
    public Object getProperty(String name) {
        return this.getSource().getAnyRef(name);
    }
}

答案 1

我想我想出了一种比手动添加到属性源稍微更习惯的方式。创建并引用它PropertySourcePropertySourceFactory@PropertySource

首先,我们有一个几乎与您拥有的完全相同的:TypesafeConfigPropertySource

public class TypesafeConfigPropertySource extends PropertySource<Config> {
    public TypesafeConfigPropertySource(String name, Config source) {
        super(name, source);
    }

    @Override
    public Object getProperty(String path) {
        if (source.hasPath(path)) {
            return source.getAnyRef(path);
        }
        return null;
    }
}

接下来,我们创建一个返回该属性源的属性源工厂

public class TypesafePropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        Config config = ConfigFactory.load(resource.getResource().getFilename()).resolve();

        String safeName = name == null ? "typeSafe" : name;
        return new TypesafeConfigPropertySource(safeName, config);
    }

}

最后,在我们的配置文件中,我们可以像引用任何其他属性源一样引用属性源,而不必自己添加属性源:PropertySource

@Configuration
@PropertySource(factory=TypesafePropertySourceFactory.class, value="someconfig.conf")
public class PropertyLoader {
    // Nothing needed here
}

答案 2

您按如下方式创建一个 PropertySource 类,它与您的类类似,不同之处在于您必须返回值或 null,并且不让 lib 引发缺少的异常

public class TypesafeConfigPropertySource extends PropertySource<Config> {

    private static final Logger LOG = getLogger(TypesafeConfigPropertySource.class);

    public TypesafeConfigPropertySource(String name, Config source) {
        super(name, source);
    }

    @Override
    public Object getProperty(String name) {
        try {
            return source.getAnyRef(name);
        } catch (ConfigException.Missing missing) {
            LOG.trace("Property requested [{}] is not set", name);
            return null;
        }
    }
}

第二步是定义一个豆子,如下所示

    @Bean
    public TypesafeConfigPropertySource provideTypesafeConfigPropertySource(
        ConfigurableEnvironment env) {

        Config conf = ConfigFactory.load().resolve();
        TypesafeConfigPropertySource source = 
                          new TypesafeConfigPropertySource("typeSafe", conf);
        MutablePropertySources sources = env.getPropertySources();
        sources.addFirst(source); // Choose if you want it first or last
        return source;

    }

如果要将属性自动连接到其他 Bean,则需要使用属性源 Bean 的注释,以确保首先加载它@DependsOn

希望它有帮助


推荐