我正在将一个工作项目从使用SpringBoot命令行参数转移到从文件中读取属性。以下是@Configuration
类的相关部分:
@Configuration
class RemoteCommunication {
@Inject
StandardServletEnvironment env
@Bean
static PropertySourcesPlaceholderConfigurer placeholderConfigurer () {
// VERIFIED this is executing...
PropertySourcesPlaceholderConfigurer target = new PropertySourcesPlaceholderConfigurer()
// VERIFIED this files exists, is readable, is a valid properties file
target.setLocation (new FileSystemResource ('/Users/me/Desktop/mess.properties'))
// A Debugger does NOT show this property source in the inject Environment
target
}
@Bean // There are many of these for different services, only one shown here.
MedicalSorIdService medicalSorIdService () {
serviceInstantiator (MedicalSorIdService_EpicSoap, 'uri.sor.id.lookup.internal')
}
// HELPER METHODS...
private <T> T serviceInstantiator (final Class<T> classToInstantiate, final String propertyKeyPrimary) {
def value = retrieveSpringPropertyFromConfigurationParameter (propertyKeyPrimary)
classToInstantiate.newInstance (value)
}
private def retrieveSpringPropertyFromConfigurationParameter (String propertyKeyPrimary) {
// PROBLEM: the property is not found in the Environment
def value = env.getProperty (propertyKeyPrimary, '')
if (value.isEmpty ()) throw new IllegalStateException ('Missing configuration parameter: ' + "\"$propertyKeyPrimary\"")
value
}
使用@Value
注入属性确实,但是如果可能的话,我宁愿直接使用Environment
。如果设置不在Environment
中,那么我不确定@Value
将它们从哪里拉出来......
env.getProperty()
继续正常工作。
欢迎任何建议!
答案 0 :(得分:15)
此处的问题是PropertySourcesPlaceholderConfigurer
和StandardServletEnvironment
或Environment
之间的区别,为简单起见。
Environment
是一个支持整个ApplicationContext
的对象,可以解析一堆属性(Environment
接口扩展PropertyResolver
)。 ConfigurableEnvironment
有一个MutablePropertySources
对象,您可以通过getPropertySources()
检索该对象。此MutablePropertySources
包含LinkedList
个PropertySource
个对象,系统会对其进行检查以解析所请求的属性。
PropertySourcesPlaceholderConfigurer
是一个具有自己状态的独立对象。它拥有自己的MutablePropertySources
对象来解析属性占位符。 PropertySourcesPlaceholderConfigurer
实现EnvironmentAware
,因此当ApplicationContext
获取它时,它会为其提供Environment
个对象。 PropertySourcesPlaceholderConfigurer
将Environment
的{{1}}添加到自己的MutablePropertySources
。然后,它还会添加您使用Resource
指定的各种setLocation()
对象作为附加属性。 这些Resource
个对象未添加到Environment
的{{1}},因此MutablePropertySources
无效。
因此,您无法直接将env.getProperty(String)
加载的属性导入PropertySourcesPlaceholderConfigurer
。您可以做的是直接添加到Environment
的{{1}}。一种方法是
Environment
或简单地(感谢@ M.Deinum)
MutablePropertySouces
请注意,添加@PostConstruct
public void setup() throws IOException {
Resource resource = new FileSystemResource("spring.properties"); // your file
Properties result = new Properties();
PropertiesLoaderUtils.fillProperties(result, resource);
env.getPropertySources().addLast(new PropertiesPropertySource("custom", result));
}
具有相同的效果,即。直接添加到@PostConstruct
public void setup() throws IOException {
env.getPropertySources().addLast(new ResourcePropertySource("custom", "file:spring.properties")); // the name 'custom' can come from anywhere
}
,但您是静态而非动态地执行此操作。
答案 1 :(得分:4)
在SpringBoot中,使用@EnableConfigurationProperties
注释就足够了 - 您无需设置PropertySourcesPlaceholderConfigurer
。
然后在POJO上添加注释@ConfigurationProperties,Spring会自动注入application.properties中定义的属性。
你也可以使用YAML文件 - 你只需要在classpath中添加适当的依赖(如SnakeYaml)
您可以在此处找到详细示例:http://spring.io/blog/2013/10/30/empowering-your-apps-with-spring-boot-s-property-support
答案 2 :(得分:1)
也许您只需将-Dspring.config.location=...
(或SPRING_CONFIG_LOCATION
设置为env var)?这有效的是在运行时将额外的配置文件添加到应用程序的默认路径,该文件优先于正常application.properties
?有关详细信息,请参阅howto docs。
答案 3 :(得分:1)
我在PropertySourcesPlaceholderConfigurer
实例化期间实现了这一目标。
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurerBean(Environment env) {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yamlFactorybean = new YamlPropertiesFactoryBean();
yamlFactorybean.setResources(determineResources(env));
PropertiesPropertySource yampProperties = new PropertiesPropertySource("yml", yamlFactorybean.getObject());
((AbstractEnvironment)env).getPropertySources().addLast(yampProperties);
propertySourcesPlaceholderConfigurer.setProperties(yamlFactorybean.getObject());
return propertySourcesPlaceholderConfigurer;
}
private static Resource[] determineResources(Environment env){
int numberOfActiveProfiles = env.getActiveProfiles().length;
ArrayList<Resource> properties = new ArrayList(numberOfActiveProfiles);
properties.add( new ClassPathResource("application.yml") );
for (String profile : env.getActiveProfiles()){
String yamlFile = "application-"+profile+".yml";
ClassPathResource props = new ClassPathResource(yamlFile);
if (!props.exists()){
log.info("Configuration file {} for profile {} does not exist");
continue;
}
properties.add(props);
}
if (log.isDebugEnabled())
log.debug("Populating application context with properties files: {}", properties);
return properties.toArray(new Resource[properties.size()]);
}