Browse Source

Recommendation for consistent @Profile declarations on overloaded @Bean methods

Issue: SPR-15266
pull/1392/head
Juergen Hoeller 9 years ago
parent
commit
5d3249f692
  1. 18
      spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
  2. 15
      spring-context/src/main/java/org/springframework/context/annotation/Profile.java
  3. 39
      src/docs/asciidoc/core/core-beans.adoc

18
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 <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">
* &#064;Profile("embedded") * &#064;Profile("development")
* &#064;Configuration * &#064;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">
* &#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} * See the {@link Profile @Profile} and {@link org.springframework.core.env.Environment}
* javadocs for further details. * javadocs for further details.
* *

15
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. * 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

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

@ -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();
---- ----

Loading…
Cancel
Save