Spring Framework 3.1 M1 released |
|

The first milestone release of Spring 3.1 has just been published [1], and this article kicks off a series of posts where I and other team members will walk through each of the major features. Even in the first milestone there's already a lot to talk about!
- Bean definition profiles
- Unified property management through Spring's new
Environmentabstraction - Enhancements to Java-based configuration with
@Featuremethods - Expanded MVC namespace support and a Java-based configuration equivalent
- Streaming support and new interception model for the
RestTemplateAPI - Comprehensive caching support
- New
c:XML namespace for concise configuration of constructor injection
Today I'll be covering the first item — a new feature we call bean definition profiles. One of our most frequent requests has been to provide a mechanism in the core container that allows for registration of different beans in different environments. The word "environment" can mean different things to different users, but a typical scenario might be registering monitoring infrastructure only when deploying an application into a performance environment, or registering customized implementations of beans for customer A vs. customer B deployments. Perhaps one of the most common cases would be working against a standalone datasource in development vs looking up that same datasource from JNDI when in QA or production. Bean definition profiles represent a general-purpose way to satisfy use cases of this kind, and we'll explore the latter use case in the examples below.
Get hands-on with a sample
I've developed a small sample to accompany this post, and you might like to take a moment now to check it out (if not, don't worry; you don't need the code to read along below). Just follow the instructions on the README at https://github.com/cbeams/spring-3.1-profiles-xml. If you're not familiar with Git, the README has instructions for SVN access, too.
Understanding the application
First let's take a look at a JUnit test case that demonstrates how transferring money between two accounts should work in our banking application:
src/test/com/bank/config/xml/IntegrationTests.java
public class IntegrationTests {
@Test
public void transferTenDollars() throws InsufficientFundsException {
ApplicationContext ctx = // instantiate the spring container
TransferService transferService = ctx.getBean(TransferService.class);
AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
assertThat(accountRepository.findById("A123").getBalance(), equalTo(100.00));
assertThat(accountRepository.findById("C456").getBalance(), equalTo(0.00));
transferService.transfer(10.00, "A123", "C456");
assertThat(accountRepository.findById("A123").getBalance(), equalTo(90.00));
assertThat(accountRepository.findById("C456").getBalance(), equalTo(10.00));
}
}
We'll get to the details of creating the Spring container in a moment, but first notice that our goal is simple — transfer $10.00 from account "A123" to account "C456". The unit test simply asserts the initial balances in the two accounts, performs the transfer, then asserts that the final balances reflect the change.
A typical XML configuration
The bean definition profiles feature is supported equally well in Spring XML as it is when using Spring @Configuration classes to configure the container, but in today's post we'll cover the XML approach as that's what most users are familiar with.
Forgetting about bean definition profiles for a moment, to configure this application in Spring XML one would traditionally do something like the snippet below. Let's assume we're early in the development process and that working against a standalone datasource is preferred. We'll use HSQLDB for convenience, but you may of course imagine the datasource of your choosing being configured.
src/main/com/bank/config/xml/transfer-service-config.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="..."> <bean id="transferService" class="com.bank.service.internal.DefaultTransferService"> <constructor-arg ref="accountRepository"/> <constructor-arg ref="feePolicy"/> </bean> <bean id="accountRepository" class="com.bank.repository.internal.JdbcAccountRepository"> <constructor-arg ref="dataSource"/> </bean> <bean id="feePolicy" class="com.bank.service.internal.ZeroFeePolicy"/> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/> <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/> </jdbc:embedded-database> </beans>
The only potentially unfamiliar item above might be the use of Spring's jdbc: namespace. Introduced in Spring 3.0, the elements within allow for easy configuration of commonly used embedded database types. It's used here just as a convenience.
With this configuration in mind, we can now finish writing the unit test we started above.
src/test/com/bank/config/xml/IntegrationTests.java
public class IntegrationTests {
@Test
public void transferTenDollars() throws InsufficientFundsException {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:/com/bank/config/xml/transfer-service-config.xml");
ctx.refresh();
TransferService transferService = ctx.getBean(TransferService.class);
AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
// perform transfer and issue assertions as above ...
}
}
Side note: We're using Spring's GenericXmlApplicationContext application context in order to load the XML configuration. Many Spring users will be more familiar with ClassPathXmlApplicationContext, which would work equally as well. As a general rule, however, GenericXmlApplicationContext is a more flexible alternative that should be generally preferred.
When running this test, the bar will be green. Our simple application is wired up by the container and we retrieve some of the beans and excercise them — nothing special to see here, folks. It gets interesting when we consider how this application will be deployed into a QA or production environment. For example, it is a common scenario for enterprises using Spring to develop web applications against Tomcat for ease-of-use reasons, but then deploy those applications into WebSphere in production. Chances are very good that the datasource for the application will be registered with the production application server's JNDI directory. This means that in order to get hold of the datasource, we must perform a JNDI lookup. Of course Spring provides great support for doing so, and one popular way is through Spring's <jee:jndi-lookup/> element. The production version of the configuration file above might end up looking something like the following:
src/main/com/bank/config/xml/transfer-service-config.xml
<beans ...> <bean id="transferService" ... /> <bean id="accountRepository" class="com.bank.repository.internal.JdbcAccountRepository"> <constructor-arg ref="dataSource"/> </bean> <bean id="feePolicy" ... /> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/> </beans>
Of course this configuration works perfectly well. The problem is how to switch between using these two variations based on the current environment. Over time, Spring users have devised a number of ways to get this done, usually relying on a combination of system environment variables and XML <import/> statements containing ${placeholder} tokens that resolve to the correct configuration file path depending on the value of an environment variable. While these and other solutions can be made to work, they're hardly what we would call "first-class" solutions provided by the container.
Enter bean definition profiles
If we generalize the example use case above of enviroment-specific bean definitions, we end up with the need to register certain bean definitions in certain contexts, while not in others. You could say that you want to register a certain profile of bean definitions in situation A, and a different profile in situation B.
In Spring 3.1, <beans/> XML documents now incorporate this new concept. We can break our configuration down into the following three files. Notice the profile="..." attribute on the *-datasource.xml files:
src/main/com/bank/config/xml/transfer-service-config.xml
<beans ...> <bean id="transferService" ... /> <bean id="accountRepository" class="com.bank.repository.internal.JdbcAccountRepository"> <constructor-arg ref="dataSource"/> </bean> <bean id="feePolicy" ... /> </beans>
src/main/com/bank/config/xml/standalone-datasource-config.xml
<beans profile="dev"> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/> <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/> </jdbc:embedded-database> </beans>
src/main/com/bank/config/xml/jndi-datasource-config.xml
<beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/> </beans>
We can then update the test case to load all three files:
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:/com/bank/config/xml/*-config.xml");
ctx.refresh();
But this is not quite enough. When running the unit test after these changes, we would see a NoSuchBeanDefinitionException thrown, because the container could not find the Spring bean named "dataSource". The reason why is that while we have clearly defined two bean definition profiles — "dev" and "production", we have not yet activated either of them.
Enter the Environment
New in 3.1 is Spring's notion of an Environment. This abstraction has been integrated throughout the container, and we'll see it several times over the blog posts in the coming days. For our purposes here, it's important to understand that the Environment contains information about which profiles (if any) are currently active. When the Spring ApplicationContext above is loading our three bean definition files, it pays close attention to the <beans profile="..."> attribute in each of them. If it is present and set to the name of a profile that is not currently active, the entire file is skipped — no bean definitions are parsed or registered.
Activating a profile can be done in several ways, but the most straightforward is to do it programmatically against the ApplicationContext API:
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");
ctx.load("classpath:/com/bank/config/xml/*-config.xml");
ctx.refresh();
At this point, running our unit test will result in the green bar. Let's break down how the container thinks about things when loading the three files that match *-config.xml:
transfer-service-config.xmldoes not specify a profile attribute at all, so it is always parsedstandalone-datasource-config.xmlspecifiesprofile="dev"and the "dev" profile is currently active, so it is parsedjndi-datasource-config.xmlspecifiesprofile="production"but the "production" profile is not currently active, so it is skipped.
The result is exactly one registered bean named "dataSource", which satisfies the dependency injection needs of the "accountRepository" bean. Everything works once again.
How then does one switch to the JNDI lookup when actually in production? Of course it's necessary to activate the "production" profile. It's fine to do this programmatically for the purpose of a unit test as above, but this approach won't be practical once the WAR file has been created and the application is ready for deployment. For this reason, profiles may also be activated declaratively through the spring.profiles.active property which may be specified through system environment variables, JVM system properties, servlet context parameters in web.xml or even as an entry in JNDI [2]. For example, you might configure web.xml as follows:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>
Note that profiles are not an "either-or" proposition; it is possible to activate multiple profiles at once. Programmatically, simply provide multiple profile names to the setActiveProfiles() method, which accepts String... varargs:
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
Declaratively, spring.profiles.active may accept a comma-separated list of profile names:
-Dspring.profiles.active="profile1,profile2"
Bean definition files may be marked as candidates for more than one profile in a similar fashion:
<beans profile="profile1,profile2"> ... </beans>
This allows for a flexible approach to decomposing your application, slicing and dicing which beans are registered under which circumstances.
Making it even simpler: introducing nested <beans/> elements
So far, bean definition profiles have provided us with a convenient mechanism for determining which beans get registered based on the deployment context of the application, but it came with one downside: Where above we had a single Spring XML configuration file, we now have three. This split was necessary in order to distinguish profile="dev" vs. profile="production" beans, because the profile attribute is specified at the <beans> element level.
With Spring 3.1, it is now possible to nest <beans/> elements within the same file. This means that we can, if desired, return to a single configuration file:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="..."> <bean id="transferService" class="com.bank.service.internal.DefaultTransferService"> <constructor-arg ref="accountRepository"/> <constructor-arg ref="feePolicy"/> </bean> <bean id="accountRepository" class="com.bank.repository.internal.JdbcAccountRepository"> <constructor-arg ref="dataSource"/> </bean> <bean id="feePolicy" class="com.bank.service.internal.ZeroFeePolicy"/> <beans profile="dev"> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/> <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/> </jdbc:embedded-database> </beans> <beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/> </beans> </beans>
spring-beans-3.1.xsd has been updated to allow this nesting, but constrained to allow such elements only as the last ones in the file. This should help provide flexibility without incurring clutter in the XML files. While this enhancement was developed in service of bean definition profiles, nested <beans/> elements are useful in general. Imagine you have a subset of beans in a given file that should be marked lazy-init="true". Rather than marking each bean, you could instead declare a nested <beans default-lazy-init="true"/> element, and all beans within will inherit that default. Beans defined elsewhere in the file will maintain the normal default of lazy-init="false". This applies for all the default-* attributes of the <beans/> element, such as default-lazy-init, default-init-method, default-destroy-method, and so on.
Caveats
There are a few things to watch out for when considering the use of bean definition profiles.
Do not use profiles if a simpler approach can get the job done. If the only thing changing between profiles is the value of properties, Spring's existing PropertyPlaceholderConfigurer / <context:property-placeholder/> may be all you need.
The set of beans registered between two profiles should probably be more similar than different. For example, if you have a radically different set of beans in dev and QA than you do in production, the question becomes: are you testing everything you should be?. As a rule of thumb, beans shouldn't differ much beyond the dev/QA split. An exception might be conditionally introducing monitoring aspects in a performance environment.
Be careful not to ship "too much" into production. If you have certain beans and class libraries present during development but that are unnecessary or unwanted in production, you run the risk of packaging all of that up and deploying it live. This is wasteful (why drag everything into the WAR if it's not needed), but also potentially insecure. Remember that the way profiles are activated is through properties. For example, if your totally insecure 'no-op password encryptor' bean definition and class are both present in the production environment, and all it takes to turn this on is the acccidental activation of the 'dev' profile, the danger is clear. A couple options for mitigating this risk might be customizing your build system to exclude unnecessary or unwanted classes from the production deployment archives, or working with the native Java SecurityManager API to disallow access to the spring.profiles.active system environment variable and/or JVM system property. Doing so will mean that even though Spring may try to read these values, it won't be able to and will move on as if they'd never been set.
Summary
That's it for now; I encourage you to take a look at the sample application and play around. For example, try running the unit tests as-is, then try setting the spring.profiles.active system property to "production" and see what happens.
In the next post in this series, we'll take a look at how bean definition profiles can be used when configuring the container with @Configuration classes instead of XML; the new @Profile annotation will help us out there.
Footnotes
[1] Milestone builds are published to http://maven.springframework.org/milestone. See the pom.xml and build.gradle files in the sample for details on how to pull from this repository.
[2] technically spring.profiles.active may be specified in any PropertySource object registered with the ApplicationContext's Environment. We'll cover the concept of property sources in a subsequent blog post.
Similar Posts
- Spring 3.1 M1: Introducing @Profile
- Spring 3.1 M2: Testing with @Configuration Classes and Profiles
- Configuration Simplifications in Spring 3.0
- Cloud Foundry for Spring Developers
- Spring 3.1 M1: Introducing FeatureSpecification support





Mark says:
Added on February 11th, 2011 at 9:28 amGreat feature.
I'm looking forward for the other features to be blogged next
Gordon Dickens says:
Added on February 11th, 2011 at 11:22 amOne of the cool features of the "c" namespace is the ability to name argument parameters. <bean class=“…” c:age=“35” c:amount=“50000”/>
Regards,
Gordon Dickens
Instructor / Mentor
Chariot Solutions
chariotsolutions.com/education
technophile.gordondickens.com
twitter.com/gdickens
vD says:
Added on February 11th, 2011 at 12:05 pmCould be one of the best features. One question left to me. web.xml is shipped within our application. How to detect the active profile for Prod/Q/Dev?
jjjjj says:
Added on February 11th, 2011 at 12:17 pmI would change comma-separated list of profile names to space-separated list, like more usual way for example in html
Keith Donald (blog author) says:
Added on February 11th, 2011 at 2:16 pmExcellent article, Chris! It's great to see Spring Framework 3.1.0.M1 here today!
We have been using bean profiles to much success in the Greenhouse reference application. In Greenhouse, we have two modes of operation: "embedded" and "standard". The "embedded" mode allows the app to run for demonstration and developer-testing purposes without any external setup required (it is also the default mode). The "standard" mode is what we run our production instance in, which connects to an external database and file store (and is activated by passing '-Dspring.profiles.active=standard' to our production server). The beans that differ between the modes include the dataSource and pictureStorage, along with the passwordEncoder and stringEncryptor. We also use PropertyPlaceholderConfigurer in conjunction with the Maven Properties plugin to vary bean property values across these environments.
Keep up the great work!
Keith
Magnus says:
Added on February 11th, 2011 at 3:33 pmIt would be really nice if the "What's New in Spring x.x"-section in the reference documentation was updated for milestones too. Maybe only with links to start with….
davidwaf says:
Added on February 12th, 2011 at 2:36 amCongratulations to the team for the fantastic work. Is servlet 3.0 available in this release?
Guy says:
Added on February 13th, 2011 at 4:14 amChris,
Thanks for an excellent review on Spring's new 'profile' feature.
A question about using profiles in test environment:
Will test environment have an in-code mechanism (such as extending @ContextConfiguration annotation or adding new behavior to SpringJUnit4ClassRunner) to support such selection ?
Guy.
Sam Brannen (blog author) says:
Added on February 13th, 2011 at 1:11 pmHi Guy,
We've already had some discussions about how to enable profile selection within tests, and I've just created a JIRA issue here to capture our thoughts:
https://jira.springsource.org/browse/SPR-7960
Regards,
Sam
Jorg Heymans says:
Added on February 14th, 2011 at 2:27 amIt is nice to finally see explicit support for environment-aware Spring configuration. For those of you that are not in a position to upgrade but would still like to use a similar mechanism I can recommend the following approach:
1) launch your VM with a system property, e.g. -Dmy.env=prod
2) Use the property in an import tag i.e.
We've been using this since 2.0.x and it works like a charm
Happy coding,
Jorg Heymans
Neale Upstone says:
Added on February 14th, 2011 at 5:18 am@Chris.
Great to see things being made explicit and consistent. Property-placeholder suffers when aggregating components with spring contexts, so I hope that during the 3.1 milestone stages, we really get some production use of this to find the corner cases.
Reading your example, I can see a few areas I'd like to be explicit:
1) Being able to define valid profile combinations. In your example, you can specify "production,dev", which is clearly not what is intended, and all too easy to do.
This could be achieved by allowing profiles combinations to be specified.
2) Going with the above, it may be wise to be able to configure specific bean definition override behaviour (i.e. 'final' bean defs). ** This would have saved a LOT of time on the project I've recently been working on, mainly due to the number of components developed by different teams with varying levels of Spring experience **
Either of the above would prevent the 'prod,dev' profile from being bootstrapped:
1)
2)
.. jndi datasource bean defs
.. dev datasource defs
Neale Upstone says:
Added on February 14th, 2011 at 5:25 amDarn XML examples in comments don't work, so:
1)
[config]
[profileOptions exclusive="production,dev,uat"/]
[profileOptions exclusive="perf,trace"/]
[/config]
2]
[beans profile="production" final="true"]
… jndi datasource bean defs
[/beans]
[beans profile="dev" final="true"]
… dev datasources
[/beans]
Anil Kumar Tatikonda says:
Added on February 15th, 2011 at 8:21 amAwesome post… very helpfull
Paul Wilson says:
Added on February 15th, 2011 at 9:17 amI trust that the extensible XML bean configuration authoring support has a nice way to create a bean definition with a given profile? I have a lot of custom XML processing code that I'd love to rework to take advantage of profiles…
Barry Ku says:
Added on February 16th, 2011 at 7:26 pmGreat to see this support. We have 6 env, dev, qa, staging1, 2, pre-production, and production in my company. I will definitely give this a try soon.
Kaare Nilsen says:
Added on February 17th, 2011 at 6:58 pmGreat news.
I have been wanting this kind of functionality for a couple of years now. So much infact that I created a small framework for this called Constretto back in 2008. It have since been used in several norwegian systems, and I have grown addicted to it
Now I hope I can deprecate the assembly capabilites of it, and focus on the core abstractions of configuration.
One experience I had was that my users soon stopped using the feature of choosing beans by environment, but more and more used targeted configuration. This can indicate that we need that functionality more.
btw, do not look for much documentation in the constretto pages, but the testcases in the source code shows lots of different usecases
Niall says:
Added on February 18th, 2011 at 7:56 amThanks for these articles on Spring 3.1 – very good. Do you have an estimate on when the 3.1 final release will be out?
Gordon Dickens says:
Added on February 18th, 2011 at 9:31 amThe final release is scheduled for the June 2011 timeframe.
Chris Beams (blog author) says:
Added on March 10th, 2011 at 9:49 pmThanks, @Neale. Would you mind adding an issue for both these requests?
Chris Beams (blog author) says:
Added on March 10th, 2011 at 10:36 pmGood point, @jjjjj. I've relaxed the restrictions on the delimiter to allow for comma, space or semicolon to be used. This is consistent with other similar elements/attributes like 'alias'. See https://jira.springsource.org/browse/SPR-8033.
Chris Beams (blog author) says:
Added on March 10th, 2011 at 10:42 pm@Paul, are you referring to tooling support in STS? If so, it will follow, but is not there yet. If you're referring to authoring custom BeanDefinitionParsers, then the idea is that you would declare your custom namespace elements within the bounds of a element. There is no explicit support in the BeanDefinition model for setting the profile(s) for individual beans.
Neale Upstone says:
Added on March 11th, 2011 at 7:09 pm@Chris: https://jira.springsource.org/browse/SPR-7982
Mark Spritzler says:
Added on March 12th, 2011 at 11:52 amChris, as always excellent writing. Thanks
I like that we are taking the approach that Grails has been using, where we can create multiple of the same beans within the same configuration file.
Speaking of grails, I wonder if we could in the future use json for our configuration files instead of xml? Sorry I digress.
Mark
Bruce says:
Added on March 22nd, 2011 at 8:41 amChris – Bean profiles will be useful, but I think your example of using them to configure a bean for test and the same bean for production in one Spring configuration file is not a good use case. Mixing test and production settings is not a standard practice and should be avoided.
Spring provides excellent support for working with JUnit (see RunWith and ContextConfiguration annotations). So a developer can easily specify a Spring configuration that will just be loaded for running tests and not become part of the production build–especially if the developer follows Maven's conventions of placing test configurations in src/test/resources.
Gordon Dickens says:
Added on March 22nd, 2011 at 9:27 amNot too long ago, I blogged about JUnit & Spring:
JUnit & Spring: What You Don't Know.
http://gordondickens.com/wordpress/2011/01/07/junit-spring-what-you-dont-know-about/
speedy says:
Added on April 9th, 2011 at 10:47 pmSo this is just what I need.
We have to mock out and external service and in integration testing use the mocked out version of the external service. This would really simplify that problem.
Adrian Smith says:
Added on May 12th, 2011 at 4:54 amWould like to see the ability to have a "default" profile that is used if none is specified. This would make it easier for production.
Chris Beams (blog author) says:
Added on May 12th, 2011 at 7:46 amHi Adrian,
Have a look at http://jira.springframework.org/browse/SPR-8203 and watch / vote for it if you like. This notion of a reserved default profile name has been requested a number of times now, and it's likely we'll put it (back) in for 3.1 M2.
Neale Upstone says:
Added on June 5th, 2011 at 8:40 amChris & Spring committers,
Isn't it about time the Mn releases (of Spring Framework and Spring Data) got published to Maven Central?
It's quite clear that they are single releases not snapshots, so why not make early adoption and feedback that bit easier.
Neale Upstone says:
Added on June 5th, 2011 at 9:56 amBy Mn, I mean Milestone releases (dunno why I didn't just type that the first time)
Chris Beams (blog author) says:
Added on June 5th, 2011 at 10:44 pmHi Neale,
We (SPR, at least) will very likely begin publishing our milestones and RCs to Maven Central starting with 3.2 M1.
Neale Upstone says:
Added on June 6th, 2011 at 4:31 amSounds good. Although I don't see any reason not to do so for 3.1.0.M2 either.
When 3.0 was coming into final milestone and RCs, I used that in projects knowing it would be final before the project hit UAT. In our more agile world, it's not inconceivable to base iterations on consuming milestone releases, with 3.1 M1 being a great example, bringing code saving features that everyone wants to use yesterday
Chris Beams (blog author) says:
Added on June 8th, 2011 at 11:49 pm@Neale, you might want to put a watch on http://jira.springframework.org/browse/SPR-8424, which I just created.
great says:
Added on July 16th, 2011 at 4:03 amgreatgreatgreat
josey jasen says:
Added on September 5th, 2011 at 6:53 amDo you have a facebook fan page? I looked for one on twitter but could
not discover one, I would really like to become a fan!
http://investorhomesolutions.com/
Ittay says:
Added on October 9th, 2011 at 8:42 amIt would be nice to be able to specify what happens when a profile is not defined "!production". It would allow easier definition when there are more than 2 mutually exclusive profiles (e.g., production, dev, test) and will allow creating default cases when a profile is not defined (the use of setDefaultProfiles means i have to code these in code and doesn't work well if there are several sets of profiles)
Chris Beams (blog author) says:
Added on October 9th, 2011 at 2:17 pm@Ittay – please comment/watch/vote on https://jira.springsource.org/browse/SPR-8728
Richard says:
Added on November 1st, 2011 at 2:24 pmWe've been using Maven's support for profiles to do a similar job. We create profile specific resource directories, e.g. dev-resources, prod-resources containing app contexts for data sources etc. then activate them with "mvn -Pdev" for example.
I'm not sure the profile support in Spring 3.1 is sufficient to tempt us away from this.
Jean says:
Added on November 29th, 2011 at 7:46 am@Chris,
the more I look at the application sample (https://github.com/cbeams/spring-3.1-profiles-xml), the more I think it's great to be able to manage deployment profile within Spring.
It really simplifies the deployment process to be able to produce a single WAR/JAR and then trigger the profile needed from an environment variable.
That being said, to be able to fully cover the configuration needs with Spring and get rid of any other system, I would count 3 parts that need to be covered:
- bean definition profile and bean properties placeholder (covered obviously)
- legacy application properties placeholder (all the properties used internally by the application and that changes between environment)
- 3rd parties system configuration properties (e.g. log4j.properties)
Your application sample doesn't have any internal properties, but it does have a typical log4j.properties for instance.
You definitely want a different log4j config in dev and in production.
If these needs aren't covered by Spring, another system is still needed to cover application configuration at deployment. You would end up with a mix of 2 systems, which is pretty bad as it makes the whole configuration more complex. (e.g. typically, a Maven profile filtering with a spring.profiles.active variable)
It'd be great to be able to cover everything with Spring, and just deploy a unique WAR/JAR, and that's it.
That's what I started to implement internally based on Spring's PropertiesLoaderSupport and PropertySourcesPlaceholderConfigurer. I'm now able to cover the 2 first items in the above list. It's pretty simple and can replace Maven profile filters.
I have started to implement an ad-hoc solution for 3rd parties like log4j, and well, I realize that Spring can't go what I consider half way on this one.
I just notice @Richard comment, and that just support my point: as it is now, it can't really lure people away from other configuration systems.
And if not, using bean profile definition means another layer of configuration, which even if very convenient, just adds another layer of complexity instead of simplifying the whole thing.
I guess it's outside of the initial scope but it could become part of a second iteration. What do you think?
Chris Beams (blog author) says:
Added on December 1st, 2011 at 12:11 am@Jean,
With regard to log4j, have you considered simply programmatically configuring log4j within one of your @Configuration classes?
This would be reasonable to do within a @PostConstruct method, for example. You could consider using Spring's own Log4jConfigurer support here. Point to one log4j config file for profile A, another for profile B.
I'm not sure I follow regarding 'legacy application properties placeholder'. Could you give an example here to clarify?
Thanks,
- Chris
Jean says:
Added on December 2nd, 2011 at 3:42 am@Chris,
I'm using Spring's Log4jConfigurer to manage log4j config. I was about to extend/tweak Log4jWebConfigurer to be able to redirect it to the right configuration according to the profile.
I'm not sure I understand how you would use @PostContruct, since Log4jConfigurer is configured in the web.xml. Good if you have the time to develop a little bit on this part.
As for what I called the "legacy application properties placeholder", I mean all the property files that are used directly by the application (without going through Spring) and that contains placeholders that are filtered at runtime somehow.
A 'classic' placeholder filter system being Maven resource filter.
It's extremely efficient but it needs to use a Maven profile, which is 'external' to the application. So at deployment time, you need to specify for which profile you want to deploy. This leads to having to one artifact per maven profile.
And this is extremely counter productive, making the deployment a very tedious and delicate process.
Being able to deploy only one artifact for all platform is a very very compelling option! And with Spring profile support it's become something much more accessible.
But since Spring profile doesn't encompass what I call '3rd parties component configuration' and 'legacy properties placeholder', it can only cover half of what's needed to switch from one system to the other (fronm'one artifact per profile' to 'one artifact containing all the profile').
Chris Beams (blog author) says:
Added on December 5th, 2011 at 8:31 am@Jean,
Feel free to propose any of the above as Improvements via JIRA. It'll be interesting to see what you've done with Log4jWebConfigurer. As regards "legacy application properties", I'm not sure whether there's anything to be done here. I would assume that any such usage would involve hard-coded paths to properties files, and there is little that Spring can do to help here, other than allowing the user to query the Environment object and load different properties files conditionally based on which profiles are active.
In any case, let's continue such discussions via individual JIRA issues. Thanks.
Gordon Dickens says:
Added on January 19th, 2012 at 9:45 amIn Spring 3.1.0.RELEASE – The ability to add profile configuration does NOT work with the DispatcherServlet. It does, however, work for the ContextLoaderListener. See https://jira.springsource.org/browse/SPR-9035
I also recently posted a blog about Profiles here http://blog.chariotsolutions.com/2012/01/spring-31-cool-new-features.html
Regards,
Gordon Dickens
twitter.com/gdickens
linkedin.com/in/gordondickens
Blog: technophile.gordondickens.com
Peter says:
Added on May 9th, 2012 at 8:39 pmI find myself wanting a this or that profile setup.
e.g.
…
…
Default profiles don't quite let me do this, as they can't cater for
…
…
…
…
I'm wanting this as my users are wanting to be able to choose between very different data sources for a variety of services at start time.
Is there anything existing that will fill this requirement?
Cheers,
Peter
Peter says:
Added on May 9th, 2012 at 8:42 pmMy xml examples got wiped out. Here they are again.
<beans profile="someProfile">…</beans>
<beans profile="!someProfile">…</beans>
and
<beans profile="someProfile">…</beans>
<beans profile="!someProfile">…</beans>
<beans profile="someOtherProfile">…</beans>
<beans profile="!someOtherProfile">…</beans>
Chris Beams (blog author) says:
Added on May 10th, 2012 at 12:04 am@Peter – please comment/watch/vote on https://jira.springsource.org/browse/SPR-8728