From 5d3249f6925f841f5b3e1395d81a78b239df0f1a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 17 Apr 2017 14:52:06 +0200 Subject: [PATCH] Recommendation for consistent @Profile declarations on overloaded @Bean methods Issue: SPR-15266 --- .../context/annotation/Configuration.java | 18 ++++++++- .../context/annotation/Profile.java | 15 ++++--- src/docs/asciidoc/core/core-beans.adoc | 39 ++++++++++++------- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java index 04627fb749b..49019333114 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java @@ -231,7 +231,7 @@ import org.springframework.stereotype.Component; * indicate they should be processed only if a given profile or profiles are active: * *
- * @Profile("embedded")
+ * @Profile("development")
  * @Configuration
  * public class EmbeddedDatabaseConfig {
  *
@@ -251,6 +251,22 @@ import org.springframework.stereotype.Component;
  *     }
  * }
* + * Alternatively, you may also declare profile conditions at the {@code @Bean} method level, + * e.g. for alternative bean variants within the same configuration class: + * + *
+ * @Configuration
+ * public class ProfileDatabaseConfig {
+ *
+ *     @Bean("dataSource")
+ *     @Profile("development")
+ *     public DataSource embeddedDatabase() { ... }
+ *
+ *     @Bean("dataSource")
+ *     @Profile("production")
+ *     public DataSource productionDatabase() { ... }
+ * }
+ * * See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment} * javadocs for further details. * diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Profile.java b/spring-context/src/main/java/org/springframework/context/annotation/Profile.java index ece57104ac6..0838238d4a5 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/Profile.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/Profile.java @@ -64,11 +64,16 @@ import org.springframework.core.env.ConfigurableEnvironment; * of which (if any) profiles are active. * *

NOTE: 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. + * 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; + * see {@code ProfileDatabaseConfig} in {@link Configuration @Configuration}'s javadoc. * *

When defining Spring beans via XML, the {@code "profile"} attribute of the * {@code } element may be used. See the documentation in the diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index e69a39eb8d9..268daacf3bf 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -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"] ---- - ` elements within the - + @@ -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(); ----