プロジェクトでtypesafeconfig(HOCON構成ファイル)を使用したいのですが、これにより、簡単で整理されたアプリケーション構成が容易になります。現在、私は通常のJavaプロパティファイル(application.properties)を使用していますが、これは大きなプロジェクトでは処理が困難です。
私のプロジェクトはSpringMVCです(Spring Bootプロジェクトではありません)。 (サービスに注入されている)Spring環境をバックアップしてtypesafeconfigでバックアップする方法はありますか? @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);
}
}
プロパティソースにPropertySource
を手動で追加するよりも、少し慣用的な方法を思いついたと思います。 PropertySourceFactory
を作成し、それを@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;
}
}
次に、そのプロパティソースを返すPropertySource factoryを作成します
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を自分で追加する代わりに、他のPropertySource
と同じようにプロパティソースを参照できます。
@Configuration
@PropertySource(factory=TypesafePropertySourceFactory.class, value="someconfig.conf")
public class PropertyLoader {
// Nothing needed here
}
次のように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;
}
}
}
2番目のステップは、Beanを次のように定義することです。
@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に自動配線する場合は、最初にロードされるように、propertysourceBeanにアノテーション@DependsOn
を使用する必要があります。
それが役に立てば幸い
Laplie Andersonは、いくつかの小さな改善を加えて答えています。
[
および:
文字を含むパスを無視する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;
}
}
上記のすべてを試しましたが失敗しました。私が抱えていた特定の問題の1つは、Beanの初期化順序でした。たとえば、タイプセーフ構成から取得され、他のプロパティでも同じであるオーバーライドされたプロパティを取得するために、フライウェイのサポートが必要でした。
M-deinumからのコメントの1つで示唆されているように、他の回答からの入力にも依存して、次のソリューションが機能します。メインアプリをロードするときにApplicationContextInitializer
を使用することで、アプリの開始時に小道具がロードされ、「env」に正しくマージされていることを確認します。
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;
@SpringBootConfiguration
@Import({MyAppConfiguration.class})
public class MyApp {
public static void main(String[] args) {
new SpringApplicationBuilder(MyApp.class)
.initializers(new MyAppContextInitializer())
.run(args);
}
}
ContextInitializer
は次のようになります。
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class MyAppContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ac) {
PropertiesLoader loader = new PropertiesLoader(ac.getEnvironment());
loader.addConfigToEnv();
}
}
PropertiesLoader
は次のように機能して、構成からプロパティをロードし、環境に詰め込みます。
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
class PropertiesLoader {
private ConfigurableEnvironment env;
public PropertiesLoader(ConfigurableEnvironment env) {
this.env = env;
}
public void addConfigToEnv() {
MutablePropertySources sources = env.getPropertySources();
Config finalConfig = ConfigFactory.load().resolve();
// you can also do other stuff like: ConfigFactory.parseFile(), use Config.withFallback to merge configs, etc.
TypesafeConfigPropertySource source = new TypesafeConfigPropertySource("typeSafe", finalConfig);
sources.addFirst(source);
}
}
また、typesafeconfigで機能するTypesafeConfigPropertySource
も必要です。
import com.typesafe.config.Config;
import org.springframework.core.env.PropertySource;
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;
}
}