Spring Environment backed by Typesafe Config

爱⌒轻易说出口 提交于 2019-11-30 11:13:21

I think I came up with a slightly more idiomatic way than manually adding the PropertySource to the property sources. Creating a PropertySourceFactory and referencing that with @PropertySource

First, we have a TypesafeConfigPropertySource almost identical to what you have:

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

Next, we create a PropertySource factory that returns that property source

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

}

And finally, in our Configuration file, we can just reference the property source like any other PropertySource instead of having to add the PropertySource ourselves:

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

You create a PropertySource class as follows, it is similar to yours with the difference that you have to return the value or null and not let the lib throw a missing exception

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

Second step is to define a bean as follows

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

    }

In cases where you want to autowire properties to other beans you need to use the annotation @DependsOn to the propertysource bean in order to ensure it is first loaded

Hope it helps

Laplie Anderson answer with some small improvements:

  • throw exception if resource not found
  • ignore path that contains [ and : characters

TypesafePropertySourceFactory.java

import java.io.IOException;

import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigParseOptions;
import com.typesafe.config.ConfigResolveOptions;

public class TypesafePropertySourceFactory implements PropertySourceFactory {

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

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

TypesafeConfigPropertySource.java

import org.springframework.core.env.PropertySource;

import com.typesafe.config.Config;

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

  @Override
  public Object getProperty(String path) {
    if (path.contains("["))
      return null;
    if (path.contains(":"))
      return null;
    if (source.hasPath(path)) {
      return source.getAnyRef(path);
    }
    return null;
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!