问题
I'm using the AbstractAnnotationConfigDispatcherServletInitializer
to configure my web application. I also have an @Configuration
class I use for creating a few beans. In this class, I use the @PropertySource
annotation to load a properties file for various settings (e.g. database connection details).
Currently, I use Maven profiles with Ant tasks to create the correct properties file(s) for my runtime environment. That is, I get Maven to move a "prod.properties" or "dev.properties" to "application.properties" (which the class uses) at build time. What I would like to do is use Spring profiles to eliminate this. I would like to be able to do the following:
@PropertySource( value = "classpath:/application-${spring.profiles.active}.properties")
I also want to set the profile without using any XML. So I would need to set the profile based on the presence of a system property. For example,
String currentEnvironment = systemProperties.getProperty("current.environment");
if (currentEnvironment == null) {
((ConfigurableEnvironment)context.getEnvironment()).setActiveProfiles("production");
} else {
((ConfigurableEnvironment)context.getEnvironment()).setActiveProfiles(currentEnvironment);
}
I am not sure where I could do this, though. According to an answer to a related question, this could be done in an override of the createRootApplicationContext
method in my initializer class. But, that answer also relies on the configuration classes being loaded before setting the profile.
Is what I want to do possible? If so, how?
回答1:
Overriding createRootApplicationContext
or createServletApplicationContext
was not working for me. I was getting various errors like illegal state exceptions and "${spring.profiles.active}" not being resolvable. Digging through the inheritance tree for AbstractAnnotationConfigDispatcherServletInitializer
I devised the following solution:
public class ApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer
{
@Override
public void onStartup(ServletContext context) throws ServletException {
super.onStartup(context);
String activeProfile = System.getProperty("your.profile.property");
if (activeProfile == null) {
activeProfile = "prod"; // or whatever you want the default to be
}
context.setInitParameter("spring.profiles.active", activeProfile);
}
}
Now you can create a configuration class like the following and it will work just fine:
@Configuration
@PropertySource( value = "classpath:application-${spring.profiles.active}.properties" )
public class MyAppBeans {
@Autowired
private Environment env;
@Bean
public Object coolBean() {
String initParam = this.env.getProperty("cool.bean.initParam");
...
return coolBean;
}
}
Of course, you would set the "your.profile.property" via VM options (-Dyour.profile.property=dev
) or container properties (e.g. Tomcat container properties).
回答2:
Instead of
@PropertySource( value = "classpath:application-${spring.profiles.active}.properties" )
You also could do
@PropertySource( value = "classpath:application.properties" )
And use some maven plugin like properties-maven-plugin (*)
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>write-active-profile-properties</goal>
</goals>
<configuration>
<outputFile>src/main/resources/application.properties</outputFile>
</configuration>
</execution>
</executions>
</plugin>
</build>
<profiles>
<profile>
<id>production</id>
<properties>
<profiles>prod</profiles>
<propertyOne>...</propertyOne>
<propertyTwo>...</propertyTwo>
</properties>
</profile>
<profile>
<id>development</id>
<properties>
<profiles>dev</profiles>
<propertyOne>...</propertyOne>
</properties>
</profile>
</profiles>
And then run
mvn <lifecycle> -P production
There is some reason in favor of passing the active profile in a system property instead of a maven parameter?
With this configuration this solution worked for me:
@Configuration
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
protected WebApplicationContext createRootApplicationContext() {
WebApplicationContext context = super.createRootApplicationContext();
((ConfigurableEnvironment) context.getEnvironment()).setActiveProfiles(profiles());
return context;
}
public String[] profiles() {
InputStream input = getClass().getClassLoader()
.getResourceAsStream("application.properties");
Properties properties = new Properties();
try {
properties.load(input);
return properties.getProperty("profiles").split(",");;
} catch (IOException e) {
e.printStackTrace();
String[] defaultProfiles = {"dev"};
return defaultProfiles;
// I really think that here we shouldn't return a default profile
}
}
}
(*) This is an old plugin (release date 2009) so maybe we should find another that do the same work, but the idea is plugin for write properties + maven profiles.
来源:https://stackoverflow.com/questions/20617827/setting-an-active-profile-for-abstractannotationconfigdispatcherservletinitializ