Support default profile (SPR-7508, SPR-7778)
'default' is now a reserved profile name, indicating
that any beans defined within that profile will be registered
unless another profile or profiles have been activated.
Examples below are expressed in XML, but apply equally when
using the @Profile annotation.
EXAMPLE 1:
<beans>
<beans profile="default">
<bean id="foo" class="com.acme.EmbeddedFooImpl"/>
</beans>
<beans profile="production">
<bean id="foo" class="com.acme.ProdFooImpl"/>
</beans>
</beans>
In the case above, the EmbeddedFooImpl 'foo' bean will be
registered if:
a) no profile is active
b) the 'default' profile has explicitly been made active
The ProdFooImpl 'foo' bean will be registered if the 'production'
profile is active.
EXAMPLE 2:
<beans profile="default,xyz">
<bean id="foo" class="java.lang.String"/>
</beans>
Bean 'foo' will be registered if any of the following are true:
a) no profile is active
b) 'xyz' profile is active
c) 'default' profile has explicitly been made active
d) both (b) and (c) are true
Note that the default profile is not to be confused with specifying no
profile at all. When the default profile is specified, beans are
registered only if no other profiles are active; whereas when no profile
is specified, bean definitions are always registered regardless of which
profiles are active.
The default profile may be configured programmatically:
environmnent.setDefaultProfile("embedded");
or declaratively through any registered PropertySource, e.g. system properties:
-DdefaultSpringProfile=embedded
Assuming either of the above, example 1 could be rewritten as follows:
<beans>
<beans profile="embedded">
<bean id="foo" class="com.acme.EmbeddedFooImpl"/>
</beans>
<beans profile="production">
<bean id="foo" class="com.acme.ProdFooImpl"/>
</beans>
</beans>
It is unlikely that use of the default profile will make sense in
conjunction with a statically specified 'springProfiles' property.
For example, if 'springProfiles' is specified as a web.xml context
param, that profile will always be active for that application,
negating the possibility of default profile bean definitions ever
being registered.
The default profile is most useful for ensuring that a valid set of
bean definitions will always be registered without forcing users
to explictly specify active profiles. In the embedded vs. production
examples above, it is assumed that the application JVM will be started
with -DspringProfiles=production when the application is in fact in
a production environment. Otherwise, the embedded/default profile bean
definitions will always be registered.
This commit is contained in:
@@ -106,45 +106,18 @@ public class AnnotatedBeanDefinitionReader {
|
||||
registerBean(annotatedClass, null, qualifiers);
|
||||
}
|
||||
|
||||
private boolean hasEligibleProfile(AnnotationMetadata metadata) {
|
||||
boolean hasEligibleProfile = false;
|
||||
if (!metadata.hasAnnotation(Profile.class.getName())) {
|
||||
hasEligibleProfile = true;
|
||||
} else {
|
||||
for (String profile : (String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) {
|
||||
if (this.environment.getActiveProfiles().contains(profile)) {
|
||||
hasEligibleProfile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasEligibleProfile;
|
||||
}
|
||||
|
||||
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
|
||||
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
|
||||
if (!hasEligibleProfile(abd.getMetadata())) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if (metadata.hasAnnotation(Profile.class.getName())) {
|
||||
if (this.environment == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> profileAttribs = metadata.getAnnotationAttributes(Profile.class.getName());
|
||||
String[] names = (String[]) profileAttribs.get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
boolean go=false;
|
||||
for (String pName : names) {
|
||||
if (this.environment.getActiveProfiles().contains(pName)) {
|
||||
go = true;
|
||||
}
|
||||
}
|
||||
if (!go) {
|
||||
AnnotationMetadata metadata = abd.getMetadata();
|
||||
|
||||
if (metadata.hasAnnotation(Profile.class.getName())) {
|
||||
String[] specifiedProfiles =
|
||||
(String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
|
||||
abd.setScope(scopeMetadata.getScopeName());
|
||||
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
@@ -296,28 +297,18 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
||||
}
|
||||
for (TypeFilter tf : this.includeFilters) {
|
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) {
|
||||
return hasEligibleProfile(metadataReader);
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
if (!metadata.hasAnnotation(Profile.class.getName())) {
|
||||
return true;
|
||||
}
|
||||
String[] specifiedProfiles =
|
||||
(String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
return this.environment.acceptsProfiles(specifiedProfiles);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasEligibleProfile(MetadataReader metadataReader) {
|
||||
boolean hasEligibleProfile = false;
|
||||
if (!metadataReader.getAnnotationMetadata().hasAnnotation(Profile.class.getName())) {
|
||||
hasEligibleProfile = true;
|
||||
} else {
|
||||
for (String profile : (String[])metadataReader.getAnnotationMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) {
|
||||
if (this.environment.getActiveProfiles().contains(profile)) {
|
||||
hasEligibleProfile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasEligibleProfile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given bean definition qualifies as candidate.
|
||||
* <p>The default implementation checks whether the class is concrete
|
||||
|
||||
@@ -101,26 +101,14 @@ class ConfigurationClassParser {
|
||||
}
|
||||
|
||||
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
|
||||
boolean hasEligibleProfile = false;
|
||||
if (this.environment == null) {
|
||||
hasEligibleProfile = true;
|
||||
} else {
|
||||
if (!configClass.getMetadata().hasAnnotation(Profile.class.getName())) {
|
||||
hasEligibleProfile = true;
|
||||
} else {
|
||||
for (String profile : (String[])configClass.getMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) {
|
||||
if (this.environment.getActiveProfiles().contains(profile)) {
|
||||
hasEligibleProfile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.environment != null && configClass.getMetadata().hasAnnotation(Profile.class.getName())) {
|
||||
String[] specifiedProfiles =
|
||||
(String[])configClass.getMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!hasEligibleProfile) {
|
||||
//logger.debug("TODO SPR-7508: issue debug statement that this class is being excluded");
|
||||
// make sure XML has a symmetrical statement as well
|
||||
return;
|
||||
}
|
||||
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
while (metadata != null) {
|
||||
|
||||
@@ -24,6 +24,16 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*
|
||||
* Components not @Profile-annotated will always be registered
|
||||
* @Profile("default") means that beans will be registered unless other profile(s) are active
|
||||
* @Profile({"xyz,default"}) means that beans will be registered if 'xyz' is active or if no profile is active
|
||||
* ConfigurableEnvironment.setDefaultProfileName(String) customizes the name of the default profile
|
||||
* 'defaultSpringProfile' property customizes the name of the default profile (usually for use as a servlet context/init param)
|
||||
* ConfigurableEnvironment.setActiveProfiles(String...) sets which profiles are active
|
||||
* 'springProfiles' sets which profiles are active (typically as a -D system property)
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user