Spring profiles are enabled using the case insensitive tokens spring.profiles.active
orspring_profiles_active
.
This token can be set as:
Spring also looks for the token, spring.profiles.default
, which can be used to set the default profile(s) if none are specified with spring.profiles.active
.
Spring 3.1 provides nested bean definitions, providing the ability to define beans for various environments:
1
2
3
4
|
<
beans
profiles
=
"dev,qa"
>
<
bean
id
=
"dataSource"
class
=
"..."
/>
<
bean
id
=
"messagingProvider"
class
=
"..."
/>
</
beans
>
|
Nested <beans>
must appear last in the file.
Beans that are used in all profiles are declared in the outer <beans>
as we always have, such as Service classes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
xsi:schemaLocation="http://www.springframework.org/schema/beans
<
bean
id
=
"businessService"
class
=
"com.c...s.springthreeone.business.SimpleBusinessServiceImpl"
/>
<
beans
profile
=
"dev,qa"
>
<
bean
id
=
"constructorBean"
class
=
"com.chariotsolutions.springthreeone.SimpleBean"
c:myString
=
"Constructor Set"
/>
<
bean
id
=
"setterBean"
class
=
"com.chariotsolutions.springthreeone.SimpleBean"
>
<
property
name
=
"myString"
value
=
"Setter Set"
/>
</
bean
>
</
beans
>
<
beans
profile
=
"prod"
>
<
bean
id
=
"setterBean"
class
=
"com.chariotsolutions.springthreeone.SimpleBean"
>
<
property
name
=
"myString"
value
=
"Setter Set - in Production YO!"
/>
</
bean
>
</
beans
>
</
beans
>
|
If we put a single <bean>
declaration at below any nested <beans>
tags we will get the exceptionorg.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'bean'
.
Multiple beans can now share the same XML "id"
In a typical scenario, we would want the DataSource bean to be called dataSource
in both all profiles. Spring now allow us to create multiple beans within an XML file with the same ID providing they are defined in different <beans>
sets. In other words, ID uniqueness is only enforced within each <beans>
set.
We can configure a class to set our profile(s) during application startup by implementing the appropriate interface. For example, we may configure an application to set different profiles based on where the application is deployed - in CloudFoundry or running as a local web application. In the web.xml
file we can include an Servlet context parameter, contextInitializerClasses,
to bootstrap this class:
1
2
3
4
|
<
context-param
>
<
param-name
>contextInitializerClasses</
param-name
>
<
param-value
>com.chariotsolutions.springthreeone.services.CloudApplicationContextInitializer</
param-value
>
</
context-param
>
|
The Initializer class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package
com.chariotsolutions.springthreeone.services;
import
org.cloudfoundry.runtime.env.CloudEnvironment;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.context.ApplicationContextInitializer;
import
org.springframework.context.ConfigurableApplicationContext;
public
class
CloudApplicationContextInitializer
implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
private
static
final
Logger logger = LoggerFactory
.getLogger(CloudApplicationContextInitializer.
class
);
@Override
public
void
initialize(ConfigurableApplicationContext applicationContext) {
CloudEnvironment env =
new
CloudEnvironment();
if
(env.getInstanceInfo() !=
null
) {
logger.info(
"Application running in cloud. API '{}'"
,
env.getCloudApiUri());
applicationContext.getEnvironment().setActiveProfiles(
"cloud"
);
applicationContext.refresh();
}
else
{
logger.info(
"Application running local"
);
applicationContext.getEnvironment().setActiveProfiles(
"dev"
);
}
}
}
|
If we are are using JavaConfig to define our beans, Spring 3.1 includes the @Profile annotation for enabling bean config files by profile(s).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package
com.chariotsolutions.springthreeone.configuration;
import
com.chariotsolutions.springthreeone.SimpleBean;
import
org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration;
import
org.springframework.context.annotation.Profile;
@Configuration
@Profile
(
"dev"
)
public
class
AppConfig {
@Bean
public
SimpleBean simpleBean() {
SimpleBean simpleBean =
new
SimpleBean();
simpleBean.setMyString(
"Ripped Pants"
);
return
simpleBean;
}
}
|
With XML configuration we can simply add the annotation @ActiveProfiles
to the JUnit test class. To include multiple profiles, use the format @ActiveProfiles(profiles = {"dev", "prod"})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package
com.chariotsolutions.springthreeone;
import
org.junit.Test;
import
org.junit.runner.RunWith;
import
org.springframework.beans.factory.NoSuchBeanDefinitionException;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.context.ApplicationContext;
import
org.springframework.test.context.ActiveProfiles;
import
org.springframework.test.context.ContextConfiguration;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import
static
junit.framework.Assert.assertNotNull;
import
static
junit.framework.Assert.assertNull;
@RunWith
(SpringJUnit4ClassRunner.
class
)
@ContextConfiguration
@ActiveProfiles
(profiles =
"dev"
)
public
class
DevBeansTest {
@Autowired
ApplicationContext applicationContext;
@Test
public
void
testDevBeans() {
SimpleBean simpleBean =
applicationContext.getBean(
"constructorBean"
, SimpleBean.
class
);
assertNotNull(simpleBean);
}
@Test
(expected = NoSuchBeanDefinitionException.
class
)
public
void
testProdBean() {
SimpleBean prodBean = applicationContext.getBean(
"prodBean"
, SimpleBean.
class
);
assertNull(prodBean);
}
}
|
JavaConfig allows us to configure Spring with or without XML configuration. If we want to test beans that are defined in a Configuration class we configure our test with the loader
and classes
arguments of the@ContextConfiguration
annotation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
com.chariotsolutions.springthreeone.configuration;
import
com.chariotsolutions.springthreeone.SimpleBean;
import
org.junit.Test;
import
org.junit.runner.RunWith;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.test.context.ActiveProfiles;
import
org.springframework.test.context.ContextConfiguration;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import
org.springframework.test.context.support.AnnotationConfigContextLoader;
import
static
org.junit.Assert.assertNotNull;
@RunWith
(SpringJUnit4ClassRunner.
class
)
@ContextConfiguration
(classes = AppConfig.
class
, loader = AnnotationConfigContextLoader.
class
)
@ActiveProfiles
(profiles =
"dev"
)
public
class
BeanConfigTest {
@Autowired
SimpleBean simpleBean;
@Test
public
void
testBeanAvailablity() {
assertNotNull(simpleBean);
}
}
|
If we desire to set the configuration in WEB.XML
, this can be done with parameters onContextLoaderListener
.
Application Context
1
2
3
4
5
6
7
8
|
<
context-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>/WEB-INF/app-config.xml</
param-value
>
</
context-param
>
<
context-param
>
<
param-name
>spring.profiles.active</
param-name
>
<
param-value
>DOUBLEUPMINT</
param-value
>
</
context-param
>
|
Log ResultsDEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.active' in [servletContextInitParams] with type [String] and value 'DOUBLEUPMINT'
Environment Variable/JVM Parameter
Setting an environment variable can be done with either spring_profiles_default
orspring_profiles_active
. In Unix/Mac it would be export SPRING_PROFILES_DEFAULT=DEVELOPMENT
for my local system.
We can also use the JVM "-D" parameter which also works with Maven when using Tomcat or Jetty plugins.
Note: Remember the tokens are NOT case sensitive and can use periods or underscores as separators. For Unix systems, you need to use the underscore, as above.
Logging of system level properties DEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.default' in [systemProperties] with type [String] and value 'dev,default'
Now we are equipped to activate various Spring bean sets, based on profiles we define. We can use traditional, XML based configuration, or the features added to support JavaConfig originally introduced in Spring 3.0.
来源:http://blog.chariotsolutions.com/2012/01/spring-31-cool-new-features.html
参考Spring官方文档:http://blog.springsource.org/2011/02/11/spring-framework-3-1-m1-released/