Recommendation for consistent @Profile declarations on overloaded @Bean methods

Issue: SPR-15266
(cherry picked from commit 5d3249f)
This commit is contained in:
Juergen Hoeller 2017-04-17 14:52:06 +02:00
parent a2b356162e
commit 6c370ed28d
4 changed files with 95 additions and 40 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -55,8 +56,9 @@ import java.lang.annotation.Target;
* @since 4.0
* @see Condition
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**

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

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -57,12 +57,24 @@ import org.springframework.core.env.ConfigurableEnvironment;
*
* <p>If a given profile is prefixed with the NOT operator ({@code !}), the annotated
* component will be registered if the profile is <em>not</em> active &mdash; for example,
* given {@code @Profile({"p1", "!p2"})}, registration will occur if profile 'p1' is active or
* if profile 'p2' is <em>not</em> active.
* given {@code @Profile({"p1", "!p2"})}, registration will occur if profile 'p1' is active
* or if profile 'p2' is <em>not</em> active.
*
* <p>If the {@code @Profile} annotation is omitted, registration will occur regardless
* 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 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
* {@code spring-beans} XSD (version 3.1 or greater) for details.
@ -78,8 +90,8 @@ import org.springframework.core.env.ConfigurableEnvironment;
* @see Conditional
* @see org.springframework.test.context.ActiveProfiles
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

View File

@ -7402,6 +7402,9 @@ jdbc.password=
}
----
[[beans-environment]]
== Environment abstraction
@ -7423,6 +7426,8 @@ on. The role of the `Environment` object with relation to properties is to provi
user with a convenient service interface for configuring property sources and resolving
properties from them.
[[beans-definition-profiles]]
=== Bean definition profiles
@ -7497,7 +7502,7 @@ can rewrite the `dataSource` configuration as follows:
[subs="verbatim,quotes"]
----
@Configuration
**@Profile("dev")**
**@Profile("development")**
public class StandaloneDataConfig {
@Bean
@ -7549,34 +7554,6 @@ of creating a custom _composed annotation_. The following example defines a cust
}
----
`@Profile` can also be declared at the method level to include only one particular bean
of a configuration class:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@Bean
**@Profile("dev")**
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
@Bean
**@Profile("production")**
public DataSource productionDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
----
[TIP]
====
If a `@Configuration` class is marked with `@Profile`, all of the `@Bean` methods and
@ -7589,8 +7566,56 @@ active. For example, given `@Profile({"p1", "!p2"})`, registration will occur if
'p1' is active or if profile 'p2' is not active.
====
`@Profile` can also be declared at the method level to include only one particular bean
of a configuration class, e.g. for alternative variants of a particular bean:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@Bean("dataSource")
**@Profile("development")**
public DataSource standaloneDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
@Bean("dataSource")
**@Profile("production")**
public DataSource jndiDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
----
[NOTE]
====
With `@Profile` on `@Bean` methods, a special scenario may apply: In the case of
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).
====
[[beans-definition-profiles-xml]]
=== XML bean definition profiles
==== XML bean definition profiles
The XML counterpart is the `profile` attribute of the `<beans>` element. Our sample
configuration above can be rewritten in two XML files as follows:
@ -7598,7 +7623,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"
@ -7637,7 +7662,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"/>
@ -7671,7 +7696,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();
----