Skip to content

Commit 5d3249f

Browse files
committed
Recommendation for consistent @Profile declarations on overloaded @bean methods
Issue: SPR-15266
1 parent 022aefd commit 5d3249f

File tree

3 files changed

+51
-21
lines changed

3 files changed

+51
-21
lines changed

spring-context/src/main/java/org/springframework/context/annotation/Configuration.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@
231231
* indicate they should be processed only if a given profile or profiles are <em>active</em>:
232232
*
233233
* <pre class="code">
234-
* &#064;Profile("embedded")
234+
* &#064;Profile("development")
235235
* &#064;Configuration
236236
* public class EmbeddedDatabaseConfig {
237237
*
@@ -251,6 +251,22 @@
251251
* }
252252
* }</pre>
253253
*
254+
* Alternatively, you may also declare profile conditions at the {@code @Bean} method level,
255+
* e.g. for alternative bean variants within the same configuration class:
256+
*
257+
* <pre class="code">
258+
* &#064;Configuration
259+
* public class ProfileDatabaseConfig {
260+
*
261+
* &#064;Bean("dataSource")
262+
* &#064;Profile("development")
263+
* public DataSource embeddedDatabase() { ... }
264+
*
265+
* &#064;Bean("dataSource")
266+
* &#064;Profile("production")
267+
* public DataSource productionDatabase() { ... }
268+
* }</pre>
269+
*
254270
* See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment}
255271
* javadocs for further details.
256272
*

spring-context/src/main/java/org/springframework/context/annotation/Profile.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,16 @@
6464
* of which (if any) profiles are active.
6565
*
6666
* <p><b>NOTE:</b> With {@code @Profile} on {@code @Bean} methods, a special scenario may
67-
* apply: In the case of overloaded {@code @Bean} methods, all {@code @Profile} declarations
68-
* from all applicable factory methods for the same bean will be merged; as a consequence,
69-
* they all need to match for the bean to become registered. {@code @Profile} can therefore
70-
* not be used to select a particular overloaded method over another; resolution between
71-
* overloaded factory methods only follows Spring's constructor resolution algorithm.
67+
* apply: In the case of overloaded {@code @Bean} methods of the same Java method name
68+
* (analogous to constructor overloading), an {@code @Profile} condition needs to be
69+
* consistently declared on all overloaded methods. If the conditions are inconsistent,
70+
* only the condition on the first declaration among the overloaded methods will matter.
71+
* {@code @Profile} can therefore not be used to select an overloaded method with a
72+
* particular argument signature over another; resolution between all factory methods
73+
* for the same bean follows Spring's constructor resolution algorithm at creation time.
74+
* <b>Use distinct Java method names pointing to the same {@link @Bean#name bean name}
75+
* if you'd like to define alternative beans with different profile conditions</b>;
76+
* see {@code ProfileDatabaseConfig} in {@link Configuration @Configuration}'s javadoc.
7277
*
7378
* <p>When defining Spring beans via XML, the {@code "profile"} attribute of the
7479
* {@code <beans>} element may be used. See the documentation in the

src/docs/asciidoc/core/core-beans.adoc

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7516,7 +7516,7 @@ can rewrite the `dataSource` configuration as follows:
75167516
[subs="verbatim,quotes"]
75177517
----
75187518
@Configuration
7519-
**@Profile("dev")**
7519+
**@Profile("development")**
75207520
public class StandaloneDataConfig {
75217521
75227522
@Bean
@@ -7581,27 +7581,27 @@ active. For example, given `@Profile({"p1", "!p2"})`, registration will occur if
75817581
====
75827582

75837583
`@Profile` can also be declared at the method level to include only one particular bean
7584-
of a configuration class:
7584+
of a configuration class, e.g. for alternative variants of a particular bean:
75857585

75867586
[source,java,indent=0]
75877587
[subs="verbatim,quotes"]
75887588
----
75897589
@Configuration
75907590
public class AppConfig {
75917591
7592-
@Bean
7593-
**@Profile("dev")**
7594-
public DataSource devDataSource() {
7592+
@Bean("dataSource")
7593+
**@Profile("development")**
7594+
public DataSource standaloneDataSource() {
75957595
return new EmbeddedDatabaseBuilder()
75967596
.setType(EmbeddedDatabaseType.HSQL)
75977597
.addScript("classpath:com/bank/config/sql/schema.sql")
75987598
.addScript("classpath:com/bank/config/sql/test-data.sql")
75997599
.build();
76007600
}
76017601
7602-
@Bean
7602+
@Bean("dataSource")
76037603
**@Profile("production")**
7604-
public DataSource productionDataSource() throws Exception {
7604+
public DataSource jndiDataSource() throws Exception {
76057605
Context ctx = new InitialContext();
76067606
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
76077607
}
@@ -7611,11 +7611,20 @@ of a configuration class:
76117611
[NOTE]
76127612
====
76137613
With `@Profile` on `@Bean` methods, a special scenario may apply: In the case of
7614-
overloaded `@Bean` methods, all `@Profile` declarations from all applicable factory
7615-
methods for the same bean will be merged; as a consequence, they all need to match
7616-
for the bean to become registered. `@Profile` can therefore not be used to select
7617-
a particular overloaded method over another; resolution between overloaded factory
7618-
methods only follows Spring's constructor resolution algorithm.
7614+
overloaded `@Bean` methods of the same Java method name (analogous to constructor
7615+
overloading), an `@Profile` condition needs to be consistently declared on all
7616+
overloaded methods. If the conditions are inconsistent, only the condition on the
7617+
first declaration among the overloaded methods will matter. `@Profile` can therefore
7618+
not be used to select an overloaded method with a particular argument signature over
7619+
another; resolution between all factory methods for the same bean follows Spring's
7620+
constructor resolution algorithm at creation time.
7621+
7622+
If you would like to define alternative beans with different profile conditions,
7623+
use distinct Java method names pointing to the same bean name via the `@Bean` name
7624+
attribute, as indicated in the example above. If the argument signatures are all
7625+
the same (e.g. all of the variants have no-arg factory methods), this is the only
7626+
way to represent such an arrangement in a valid Java class in the first place
7627+
(since there can only be one method of a particular name and argument signature).
76197628
====
76207629

76217630

@@ -7628,7 +7637,7 @@ configuration above can be rewritten in two XML files as follows:
76287637
[source,xml,indent=0]
76297638
[subs="verbatim,quotes"]
76307639
----
7631-
<beans profile="dev"
7640+
<beans profile="development"
76327641
xmlns="http://www.springframework.org/schema/beans"
76337642
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
76347643
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
76677676
76687677
<!-- other bean definitions -->
76697678
7670-
<beans profile="dev">
7679+
<beans profile="development">
76717680
<jdbc:embedded-database id="dataSource">
76727681
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
76737682
<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
77017710
[subs="verbatim,quotes"]
77027711
----
77037712
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
7704-
ctx.getEnvironment().setActiveProfiles("dev");
7713+
ctx.getEnvironment().setActiveProfiles("development");
77057714
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
77067715
ctx.refresh();
77077716
----

0 commit comments

Comments
 (0)