我想添加一个可用于读取应用程序中属性值的新属性源。我想用Spring做这件事。我在@Configuration类中有一段这样的代码:
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
MutablePropertySources sources = new MutablePropertySources();
MyCustomPropertySource propertySource = new MyCustomPropertySource("my custom property source");
sources.addFirst(propertySource);
properties.setPropertySources(sources);
return properties;
}
这看起来效果很好。但是,它还在做的是覆盖其他属性值(例如spring boot使用的application.properties文件中的server.port属性),我不想覆盖它们。所以基本的问题是添加此属性源的最佳方法是什么,但不要覆盖其他属性。有没有什么方法可以获取现有的属性资源并简单地添加它?
答案 0 :(得分:1)
您可能尝试的一件事是将IgnoreUnresolvablePlaceholders设置为TRUE。我有一个类似的问题,我能够以这种方式解决。在我的情况下,我有另一个占位符配置器,它正在工作 - 但第二个中的属性没有被解析,除非我将此属性设置为TRUE。
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(Boolean.TRUE);
return propertySourcesPlaceholderConfigurer;
}
答案 1 :(得分:1)
我通过在Spring Boot应用程序中添加一个自定义的启动器来实现这一目的:
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
new SpringApplicationBuilder(VftApp.class)
.initializers(new MyContextInitializer()) // <---- here
.run(args);
}
}
MyContextInitializer
包含:-
public class MyContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
// Create map for properites and add first (important)
Map<String, Object> myProperties = new HashMap<>();
myProperties.put("some-prop", "custom-value");
environment.getPropertySources().addFirst(
new MapPropertySource("my-props", myProperties));
}
}
请注意,如果您的application.yaml
包含:-
some-prop: some-value
another-prop: this is ${some-prop} property
然后,initialize
方法会将some-prop
更新为custom-value
,并在应用加载时在运行时具有以下值:
some-prop: custom-value
another-prop: this is custom-value property
请注意,如果initialize
方法进行了简单的System.setProperty
调用,即
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
System.setProperty("some-prop", "custom-value");
}
...然后another-prop
等于this is some-value property
,这不是我们通常想要的(并且我们失去了Spring config属性解析的能力)。
答案 2 :(得分:0)
您可以在初始化后将propertySource直接添加到环境中。
编辑:由于这是在处理完类之后完成的,因此您不能指望@Value
注释从同一@Configuration
类中的此特定PropertySource中获取任何内容 - 或之前加载的任何其他内容。
@Configuration
public class YourPropertyConfigClass{
@Value("${fromCustomSource}")
String prop; // failing - property source not yet existing
@Autowired
ConfigurableEnvironment env;
@PostConstruct
public void init() throws Exception {
env.getPropertySources().addFirst(
new MyCustomPropertySource("my custom property source"));
}
}
@Configuration
@DependsOn("YourPropertyConfigClass")
public class PropertyUser {
@Value("${fromCustomSource}")
String prop; // not failing
}
您可以将@PostConstruct
移动到单独的@Configuration
类,并使用这些属性标记其他类@DependOn("YourPropertyConfigClass")
(这有效 - 但也许有更好的方法来强制配置顺序?)
无论如何 - 只有使用MyCustomPropertySource
注释无法简单地添加@PropertySource("file.properties")
,这是值得的 - 这将解决简单属性文件的问题。
答案 3 :(得分:0)
如果您实现PropertySourceFactory:
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
public class CustomPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) {
...
}
}
您可以使用以下属性来源:
@PropertySource(name="custom-prop-source", value="", factory=CustomPropertySourceFactory.class)
有点hack-ish,但它确实有效。
答案 4 :(得分:0)
另一种可能性(经过大量实验,这对我有用)是在PropertySource
中声明您的ApplicationContextInitializer
,然后将其注入您的SpringBootServletInitializer
:>
public class MyPropertyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger logger = LoggerFactory.getLogger(ApplicationPropertyInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MyPropertySource ps = new MyPropertySource();
applicationContext.getEnvironment().getPropertySources().addFirst(ps);
}
}
public class MyInitializer extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return super.configure(builder.initializers(new MyPropertyInitializer()));
}
}