Recommendation for consistent @Profile declarations on overloaded @Bean methods
Issue: SPR-15266
This commit is contained in:
@@ -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>:
|
* indicate they should be processed only if a given profile or profiles are <em>active</em>:
|
||||||
*
|
*
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* @Profile("embedded")
|
* @Profile("development")
|
||||||
* @Configuration
|
* @Configuration
|
||||||
* public class EmbeddedDatabaseConfig {
|
* public class EmbeddedDatabaseConfig {
|
||||||
*
|
*
|
||||||
@@ -251,6 +251,22 @@ import org.springframework.stereotype.Component;
|
|||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</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">
|
||||||
|
* @Configuration
|
||||||
|
* public class ProfileDatabaseConfig {
|
||||||
|
*
|
||||||
|
* @Bean("dataSource")
|
||||||
|
* @Profile("development")
|
||||||
|
* public DataSource embeddedDatabase() { ... }
|
||||||
|
*
|
||||||
|
* @Bean("dataSource")
|
||||||
|
* @Profile("production")
|
||||||
|
* public DataSource productionDatabase() { ... }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
* See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment}
|
* See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment}
|
||||||
* javadocs for further details.
|
* javadocs for further details.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -64,11 +64,16 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
|||||||
* of which (if any) profiles are active.
|
* of which (if any) profiles are active.
|
||||||
*
|
*
|
||||||
* <p><b>NOTE:</b> With {@code @Profile} on {@code @Bean} methods, a special scenario may
|
* <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
|
* apply: In the case of overloaded {@code @Bean} methods of the same Java method name
|
||||||
* from all applicable factory methods for the same bean will be merged; as a consequence,
|
* (analogous to constructor overloading), an {@code @Profile} condition needs to be
|
||||||
* they all need to match for the bean to become registered. {@code @Profile} can therefore
|
* consistently declared on all overloaded methods. If the conditions are inconsistent,
|
||||||
* not be used to select a particular overloaded method over another; resolution between
|
* only the condition on the first declaration among the overloaded methods will matter.
|
||||||
* overloaded factory methods only follows Spring's constructor resolution algorithm.
|
* {@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
|
* <p>When defining Spring beans via XML, the {@code "profile"} attribute of the
|
||||||
* {@code <beans>} element may be used. See the documentation in the
|
* {@code <beans>} element may be used. See the documentation in the
|
||||||
|
|||||||
@@ -7516,7 +7516,7 @@ can rewrite the `dataSource` configuration as follows:
|
|||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
**@Profile("dev")**
|
**@Profile("development")**
|
||||||
public class StandaloneDataConfig {
|
public class StandaloneDataConfig {
|
||||||
|
|
||||||
@Bean
|
@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
|
`@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]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
@@ -7589,9 +7589,9 @@ of a configuration class:
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean("dataSource")
|
||||||
**@Profile("dev")**
|
**@Profile("development")**
|
||||||
public DataSource devDataSource() {
|
public DataSource standaloneDataSource() {
|
||||||
return new EmbeddedDatabaseBuilder()
|
return new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.HSQL)
|
.setType(EmbeddedDatabaseType.HSQL)
|
||||||
.addScript("classpath:com/bank/config/sql/schema.sql")
|
.addScript("classpath:com/bank/config/sql/schema.sql")
|
||||||
@@ -7599,9 +7599,9 @@ of a configuration class:
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean("dataSource")
|
||||||
**@Profile("production")**
|
**@Profile("production")**
|
||||||
public DataSource productionDataSource() throws Exception {
|
public DataSource jndiDataSource() throws Exception {
|
||||||
Context ctx = new InitialContext();
|
Context ctx = new InitialContext();
|
||||||
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
|
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
|
||||||
}
|
}
|
||||||
@@ -7611,11 +7611,20 @@ of a configuration class:
|
|||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
With `@Profile` on `@Bean` methods, a special scenario may apply: In the case of
|
With `@Profile` on `@Bean` methods, a special scenario may apply: In the case of
|
||||||
overloaded `@Bean` methods, all `@Profile` declarations from all applicable factory
|
overloaded `@Bean` methods of the same Java method name (analogous to constructor
|
||||||
methods for the same bean will be merged; as a consequence, they all need to match
|
overloading), an `@Profile` condition needs to be consistently declared on all
|
||||||
for the bean to become registered. `@Profile` can therefore not be used to select
|
overloaded methods. If the conditions are inconsistent, only the condition on the
|
||||||
a particular overloaded method over another; resolution between overloaded factory
|
first declaration among the overloaded methods will matter. `@Profile` can therefore
|
||||||
methods only follows Spring's constructor resolution algorithm.
|
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]
|
[source,xml,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
<beans profile="dev"
|
<beans profile="development"
|
||||||
xmlns="http://www.springframework.org/schema/beans"
|
xmlns="http://www.springframework.org/schema/beans"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
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 -->
|
<!-- other bean definitions -->
|
||||||
|
|
||||||
<beans profile="dev">
|
<beans profile="development">
|
||||||
<jdbc:embedded-database id="dataSource">
|
<jdbc:embedded-database id="dataSource">
|
||||||
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
|
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
|
||||||
<jdbc:script location="classpath:com/bank/config/sql/test-data.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"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
ctx.getEnvironment().setActiveProfiles("dev");
|
ctx.getEnvironment().setActiveProfiles("development");
|
||||||
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
|
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
|
||||||
ctx.refresh();
|
ctx.refresh();
|
||||||
----
|
----
|
||||||
|
|||||||
Reference in New Issue
Block a user