Recommendation for consistent @Profile declarations on overloaded @Bean methods

Issue: SPR-15266
This commit is contained in:
Juergen Hoeller 2017-04-17 14:52:06 +02:00
parent 022aefdfe8
commit 5d3249f692
3 changed files with 51 additions and 21 deletions

View File

@ -231,7 +231,7 @@ import org.springframework.stereotype.Component;
* indicate they should be processed only if a given profile or profiles are <em>active</em>:
*
* <pre class="code">
* &#064;Profile("embedded")
* &#064;Profile("development")
* &#064;Configuration
* public class EmbeddedDatabaseConfig {
*
@ -251,6 +251,22 @@ import org.springframework.stereotype.Component;
* }
* }</pre>
*
* Alternatively, you may also declare profile conditions at the {@code @Bean} method level,
* e.g. for alternative bean variants within the same configuration class:
*
* <pre class="code">
* &#064;Configuration
* public class ProfileDatabaseConfig {
*
* &#064;Bean("dataSource")
* &#064;Profile("development")
* public DataSource embeddedDatabase() { ... }
*
* &#064;Bean("dataSource")
* &#064;Profile("production")
* public DataSource productionDatabase() { ... }
* }</pre>
*
* See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment}
* javadocs for further details.
*

View File

@ -64,11 +64,16 @@ import org.springframework.core.env.ConfigurableEnvironment;
* of which (if any) profiles are active.
*
* <p><b>NOTE:</b> With {@code @Profile} on {@code @Bean} methods, a special scenario may
* apply: In the case of overloaded {@code @Bean} methods, all {@code @Profile} declarations
* from all applicable factory methods for the same bean will be merged; as a consequence,
* they all need to match for the bean to become registered. {@code @Profile} can therefore
* not be used to select a particular overloaded method over another; resolution between
* overloaded factory methods only follows Spring's constructor resolution algorithm.
* apply: In the case of overloaded {@code @Bean} methods of the same Java method name
* (analogous to constructor overloading), an {@code @Profile} condition needs to be
* consistently declared on all overloaded methods. If the conditions are inconsistent,
* only the condition on the first declaration among the overloaded methods will matter.
* {@code @Profile} can therefore not be used to select an overloaded method with a
* particular argument signature over another; resolution between all factory methods
* for the same bean follows Spring's constructor resolution algorithm at creation time.
* <b>Use distinct Java method names pointing to the same {@link @Bean#name bean name}
* if you'd like to define alternative beans with different profile conditions</b>;
* see {@code ProfileDatabaseConfig} in {@link Configuration @Configuration}'s javadoc.
*
* <p>When defining Spring beans via XML, the {@code "profile"} attribute of the
* {@code <beans>} element may be used. See the documentation in the

View File

@ -7516,7 +7516,7 @@ can rewrite the `dataSource` configuration as follows:
[subs="verbatim,quotes"]
----
@Configuration
**@Profile("dev")**
**@Profile("development")**
public class StandaloneDataConfig {
@Bean
@ -7581,7 +7581,7 @@ active. For example, given `@Profile({"p1", "!p2"})`, registration will occur if
====
`@Profile` can also be declared at the method level to include only one particular bean
of a configuration class:
of a configuration class, e.g. for alternative variants of a particular bean:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -7589,9 +7589,9 @@ of a configuration class:
@Configuration
public class AppConfig {
@Bean
**@Profile("dev")**
public DataSource devDataSource() {
@Bean("dataSource")
**@Profile("development")**
public DataSource standaloneDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
@ -7599,9 +7599,9 @@ of a configuration class:
.build();
}
@Bean
@Bean("dataSource")
**@Profile("production")**
public DataSource productionDataSource() throws Exception {
public DataSource jndiDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
@ -7611,11 +7611,20 @@ of a configuration class:
[NOTE]
====
With `@Profile` on `@Bean` methods, a special scenario may apply: In the case of
overloaded `@Bean` methods, all `@Profile` declarations from all applicable factory
methods for the same bean will be merged; as a consequence, they all need to match
for the bean to become registered. `@Profile` can therefore not be used to select
a particular overloaded method over another; resolution between overloaded factory
methods only follows Spring's constructor resolution algorithm.
overloaded `@Bean` methods of the same Java method name (analogous to constructor
overloading), an `@Profile` condition needs to be consistently declared on all
overloaded methods. If the conditions are inconsistent, only the condition on the
first declaration among the overloaded methods will matter. `@Profile` can therefore
not be used to select an overloaded method with a particular argument signature over
another; resolution between all factory methods for the same bean follows Spring's
constructor resolution algorithm at creation time.
If you would like to define alternative beans with different profile conditions,
use distinct Java method names pointing to the same bean name via the `@Bean` name
attribute, as indicated in the example above. If the argument signatures are all
the same (e.g. all of the variants have no-arg factory methods), this is the only
way to represent such an arrangement in a valid Java class in the first place
(since there can only be one method of a particular name and argument signature).
====
@ -7628,7 +7637,7 @@ configuration above can be rewritten in two XML files as follows:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<beans profile="dev"
<beans profile="development"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
@ -7667,7 +7676,7 @@ It is also possible to avoid that split and nest `<beans/>` elements within the
<!-- other bean definitions -->
<beans profile="dev">
<beans profile="development">
<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"/>
@ -7701,7 +7710,7 @@ it programmatically against the `Environment` API which is available via an
[subs="verbatim,quotes"]
----
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
----