From 2a4e1c98da889f12e70cdb7f6b948382bbe06abd Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 8 Dec 2010 07:59:25 +0000 Subject: [PATCH] Eliminate reserved 'default' profile (SPR-7778) There is no longer a reserved default profile named 'default'. Rather, users must explicitly specify a default profile or profiles via ConfigurableEnvironment.setDefaultProfiles(String...) - or - spring.profile.default="pD1,pD2" Per above, the setDefaultProfile(String) method now accepts a variable number of profile names (one or more). This is symmetrical with the existing setActiveProfiles(String...) method. A typical scenario might involve setting both a default profile as a servlet context property in web.xml and then setting an active profile when deploying to production. git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3809 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../beans/factory/xml/spring-beans-3.1.xsd | 8 +- .../xml/ProfileXmlBeanDefinitionTests.java | 52 ++++++++++--- .../context/annotation/Profile.java | 9 ++- ...anningCandidateComponentProviderTests.java | 12 ++- .../core/env/AbstractEnvironment.java | 78 ++++++++----------- .../core/env/ConfigurableEnvironment.java | 6 +- .../springframework/core/env/Environment.java | 2 +- .../core/env/DefaultEnvironmentTests.java | 18 +++-- 8 files changed, 103 insertions(+), 82 deletions(-) diff --git a/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd index 68ffbf9ce9c..e4837178674 100644 --- a/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd +++ b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd @@ -84,13 +84,13 @@ TODO:SPR-7508: Document profile annotation: * may be comma-delimited * empty profile means beans 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 - * 'spring.profile.default' property customizes the name of the default profile (usually for use as a * ConfigurableEnvironment.setActiveProfiles(String...) sets which profiles are active * 'spring.profile.active' sets which profiles are active (typically as a -D system property) servlet context/init param) + * ConfigurableEnvironment.setDefaultProfiles(String...) or 'spring.profile.default' property specifies one + or more default profiles, e.g., 'default' + * if 'default' is specified as a default profile, `profile="xyz,default"` means that beans will be + registered if 'xyz' is active or if no profile is active ]]> diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java index a4841f0dae8..fcf4d061716 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java @@ -86,21 +86,11 @@ public class ProfileXmlBeanDefinitionTests { @Test public void testDefaultProfile() { - assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean()); - assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, "other"), not(containsTargetBean())); - - assertThat(beanFactoryFor(DEFAULT_AND_DEV_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean()); - assertThat(beanFactoryFor(DEFAULT_AND_DEV_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean()); - assertThat(beanFactoryFor(DEFAULT_AND_DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean())); - } - - @Test - public void testCustomDefaultProfile() { { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); ConfigurableEnvironment env = new DefaultEnvironment(); - env.setDefaultProfile("custom-default"); + env.setDefaultProfiles("custom-default"); reader.setEnvironment(env); reader.loadBeanDefinitions(new ClassPathResource(DEFAULT_ELIGIBLE_XML, getClass())); @@ -110,7 +100,7 @@ public class ProfileXmlBeanDefinitionTests { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); ConfigurableEnvironment env = new DefaultEnvironment(); - env.setDefaultProfile("custom-default"); + env.setDefaultProfiles("custom-default"); reader.setEnvironment(env); reader.loadBeanDefinitions(new ClassPathResource(CUSTOM_DEFAULT_ELIGIBLE_XML, getClass())); @@ -118,6 +108,44 @@ public class ProfileXmlBeanDefinitionTests { } } + @Test + public void testDefaultAndNonDefaultProfile() { + assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, "other"), not(containsTargetBean())); + + { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + ConfigurableEnvironment env = new DefaultEnvironment(); + env.setActiveProfiles(DEV_ACTIVE); + env.setDefaultProfiles("default"); + reader.setEnvironment(env); + reader.loadBeanDefinitions(new ClassPathResource(DEFAULT_AND_DEV_ELIGIBLE_XML, getClass())); + assertThat(beanFactory, containsTargetBean()); + } + { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + ConfigurableEnvironment env = new DefaultEnvironment(); + // env.setActiveProfiles(DEV_ACTIVE); + env.setDefaultProfiles("default"); + reader.setEnvironment(env); + reader.loadBeanDefinitions(new ClassPathResource(DEFAULT_AND_DEV_ELIGIBLE_XML, getClass())); + assertThat(beanFactory, containsTargetBean()); + } + { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + ConfigurableEnvironment env = new DefaultEnvironment(); + // env.setActiveProfiles(DEV_ACTIVE); + //env.setDefaultProfiles("default"); + reader.setEnvironment(env); + reader.loadBeanDefinitions(new ClassPathResource(DEFAULT_AND_DEV_ELIGIBLE_XML, getClass())); + assertThat(beanFactory, not(containsTargetBean())); + } + } + + private BeanDefinitionRegistry beanFactoryFor(String xmlName, String... activeProfiles) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java index 744463556da..6e6c2ea88cb 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java @@ -27,12 +27,13 @@ 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 - * 'spring.profile.default' 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 * 'spring.profile.active' sets which profiles are active (typically as a -D system property) + servlet context/init param) + * ConfigurableEnvironment.setDefaultProfiles(String...) or 'spring.profile.default' property specifies one + or more default profiles, e.g., 'default' + * if 'default' is specified as a default profile, @Profile({"xyz,default}) means that beans will be + registered if 'xyz' is active or if no profile is active * * @author Chris Beams * @since 3.1 diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java index 813f63665ea..bf27e63b672 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -29,7 +29,6 @@ import java.util.regex.Pattern; import org.aspectj.lang.annotation.Aspect; import org.junit.Test; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.DefaultEnvironment; import org.springframework.core.type.filter.AnnotationTypeFilter; @@ -59,6 +58,7 @@ public class ClassPathScanningCandidateComponentProviderTests { private static final String TEST_BASE_PACKAGE = "example.scannable"; private static final String TEST_PROFILE_PACKAGE = "example.profilescan"; + private static final String TEST_DEFAULT_PROFILE_NAME = "testDefault"; @Test @@ -219,6 +219,7 @@ public class ClassPathScanningCandidateComponentProviderTests { @Test public void testIntegrationWithAnnotationConfigApplicationContext_defaultProfile() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setDefaultProfiles(TEST_DEFAULT_PROFILE_NAME); // no active profiles are set ctx.register(DefaultProfileAnnotatedComponent.class); ctx.refresh(); @@ -231,6 +232,7 @@ public class ClassPathScanningCandidateComponentProviderTests { String beanName = DefaultAndDevProfileAnnotatedComponent.BEAN_NAME; { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setDefaultProfiles(TEST_DEFAULT_PROFILE_NAME); // no active profiles are set ctx.register(beanClass); ctx.refresh(); @@ -238,6 +240,7 @@ public class ClassPathScanningCandidateComponentProviderTests { } { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setDefaultProfiles(TEST_DEFAULT_PROFILE_NAME); ctx.getEnvironment().setActiveProfiles("dev"); ctx.register(beanClass); ctx.refresh(); @@ -245,6 +248,7 @@ public class ClassPathScanningCandidateComponentProviderTests { } { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setDefaultProfiles(TEST_DEFAULT_PROFILE_NAME); ctx.getEnvironment().setActiveProfiles("other"); ctx.register(beanClass); ctx.refresh(); @@ -263,13 +267,13 @@ public class ClassPathScanningCandidateComponentProviderTests { } - @Profile(AbstractEnvironment.DEFAULT_PROFILE_NAME) + @Profile(TEST_DEFAULT_PROFILE_NAME) @Component(DefaultProfileAnnotatedComponent.BEAN_NAME) private static class DefaultProfileAnnotatedComponent { static final String BEAN_NAME = "defaultProfileAnnotatedComponent"; } - @Profile({AbstractEnvironment.DEFAULT_PROFILE_NAME,"dev"}) + @Profile({TEST_DEFAULT_PROFILE_NAME,"dev"}) @Component(DefaultAndDevProfileAnnotatedComponent.BEAN_NAME) private static class DefaultAndDevProfileAnnotatedComponent { static final String BEAN_NAME = "defaultAndDevProfileAnnotatedComponent"; diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java index dbabdf77b99..e58fd3e961c 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java @@ -40,6 +40,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.ConversionServiceFactory; import org.springframework.util.PropertyPlaceholderHelper; import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; +import org.springframework.util.StringUtils; /** @@ -51,32 +52,23 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; public abstract class AbstractEnvironment implements ConfigurableEnvironment { public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profile.active"; - - public static final String DEFAULT_PROFILE_PROPERTY_NAME = "spring.profile.default"; - - /** - * Default name of the default profile. Override with - * {@link #setDefaultProfile(String)}. - * - * @see #setDefaultProfile(String) - */ - public static final String DEFAULT_PROFILE_NAME = "default"; + public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profile.default"; protected final Log logger = LogFactory.getLog(getClass()); + private Set activeProfiles = new LinkedHashSet(); + private Set defaultProfiles = new LinkedHashSet(); + + private LinkedList> propertySources = new LinkedList>(); + private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + private final PropertyPlaceholderHelper nonStrictHelper = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true); private final PropertyPlaceholderHelper strictHelper = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false); - private Set activeProfiles = new LinkedHashSet(); - private LinkedList> propertySources = new LinkedList>(); - private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); - private boolean explicitlySetProfiles; - - private String defaultProfile = DEFAULT_PROFILE_NAME; public void addPropertySource(PropertySource propertySource) { @@ -187,28 +179,35 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { } public Set getActiveProfiles() { - doGetProfiles(); + if (this.activeProfiles.isEmpty()) { + String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME); + if (StringUtils.hasText(profiles)) { + this.activeProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles)); + } + } return Collections.unmodifiableSet(activeProfiles); } - private void doGetProfiles() { - if (explicitlySetProfiles) - return; - - String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME); - if (profiles == null || profiles.equals("")) { - return; - } - - this.activeProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles)); - } - public void setActiveProfiles(String... profiles) { - explicitlySetProfiles = true; this.activeProfiles.clear(); this.activeProfiles.addAll(Arrays.asList(profiles)); } + public Set getDefaultProfiles() { + if (this.defaultProfiles.isEmpty()) { + String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME); + if (StringUtils.hasText(profiles)) { + this.defaultProfiles = commaDelimitedListToSet(profiles); + } + } + return Collections.unmodifiableSet(this.defaultProfiles); + } + + public void setDefaultProfiles(String... profiles) { + this.defaultProfiles.clear(); + this.defaultProfiles.addAll(Arrays.asList(profiles)); + } + public Map getSystemEnvironment() { Map systemEnvironment; try { @@ -282,9 +281,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { public boolean acceptsProfiles(String[] specifiedProfiles) { boolean activeProfileFound = false; Set activeProfiles = this.getActiveProfiles(); + Set defaultProfiles = this.getDefaultProfiles(); for (String profile : specifiedProfiles) { if (activeProfiles.contains(profile) - || (activeProfiles.isEmpty() && profile.equals(this.getDefaultProfile()))) { + || (activeProfiles.isEmpty() && defaultProfiles.contains(profile))) { activeProfileFound = true; break; } @@ -292,18 +292,6 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { return activeProfileFound; } - public String getDefaultProfile() { - String defaultProfileProperty = getProperty(DEFAULT_PROFILE_PROPERTY_NAME); - if (defaultProfileProperty != null) { - return defaultProfileProperty; - } - return defaultProfile; - } - - public void setDefaultProfile(String defaultProfile) { - this.defaultProfile = defaultProfile; - } - private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) { return helper.replacePlaceholders(text, new PlaceholderResolver() { public String resolvePlaceholder(String placeholderName) { @@ -314,8 +302,8 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { @Override public String toString() { - return getClass().getSimpleName() + " [activeProfiles=" + activeProfiles - + ", propertySources=" + propertySources + "]"; + return String.format("%s [activeProfiles=%s, defaultProfiles=%s, propertySources=%s]", + getClass().getSimpleName(), activeProfiles, defaultProfiles, propertySources); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java index 827ae5d4e5b..ea88622ced6 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java @@ -30,10 +30,8 @@ public interface ConfigurableEnvironment extends Environment, PropertySourceAggr void setActiveProfiles(String... profiles); /** - * Set the default profile name to be used instead of 'default' - * - * @param defaultProfile + * TODO SPR-7508: document */ - void setDefaultProfile(String defaultProfile); + void setDefaultProfiles(String... profiles); } diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java index 90c073c2367..b85ebc2a351 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java @@ -38,7 +38,7 @@ public interface Environment { /** * TODO SPR-7508: document */ - String getDefaultProfile(); + Set getDefaultProfiles(); /** * TODO SPR-7508: document diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java index ff7af9459d0..0d233a15c8c 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java @@ -25,12 +25,12 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.matchers.JUnitMatchers.hasItem; import static org.junit.matchers.JUnitMatchers.hasItems; import static org.springframework.core.env.AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME; -import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILE_NAME; -import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILE_PROPERTY_NAME; +import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME; import static org.springframework.core.env.DefaultEnvironmentTests.CollectionMatchers.isEmpty; import java.lang.reflect.Field; @@ -239,26 +239,28 @@ public class DefaultEnvironmentTests { @Test public void systemPropertiesResoloutionOfMultipleProfiles() { assertThat(environment.getActiveProfiles(), isEmpty()); - System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar"); assertThat(environment.getActiveProfiles(), hasItems("foo", "bar")); + System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); + } + @Test + public void systemPropertiesResolutionOfMulitpleProfiles_withWhitespace() { + assertThat(environment.getActiveProfiles(), isEmpty()); System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace - assertThat(environment.getActiveProfiles(), not(hasItems("foo", "bar"))); assertThat(environment.getActiveProfiles(), hasItems("bar", "baz")); - System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); } @Test public void environmentResolutionOfDefaultSpringProfileProperty_noneSet() { - assertThat(environment.getDefaultProfile(), equalTo(DEFAULT_PROFILE_NAME)); + assertThat(environment.getDefaultProfiles(), isEmpty()); } @Test public void environmentResolutionOfDefaultSpringProfileProperty_isSet() { - testProperties.setProperty(DEFAULT_PROFILE_PROPERTY_NAME, "custom-default"); - assertThat(environment.getDefaultProfile(), equalTo("custom-default")); + testProperties.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "custom-default"); + assertTrue(environment.getDefaultProfiles().contains("custom-default")); } @Test