M1 cut of environment, profiles and property work (SPR-7508)

Decomposed Environment interface into PropertySources, PropertyResolver
objects

    Environment interface and implementations are still present, but
    simpler.

    PropertySources container aggregates PropertySource objects;
    PropertyResolver provides search, conversion, placeholder
    replacement. Single implementation for now is
    PropertySourcesPlaceholderResolver

Renamed EnvironmentAwarePropertyPlaceholderConfigurer to
PropertySourcesPlaceholderConfigurer

    <context:property-placeholder/> now registers PSPC by default, else
    PPC if systemPropertiesMode* settings are involved

Refined configuration and behavior of default profiles

    See Environment interface Javadoc for details

Added Portlet implementations of relevant interfaces:

    * DefaultPortletEnvironment
    * PortletConfigPropertySource, PortletContextPropertySource
    * Integrated each appropriately throughout Portlet app contexts

Added protected 'createEnvironment()' method to AbstractApplicationContext

    Subclasses can override at will to supply a custom Environment
    implementation.  In practice throughout the framework, this is how
    Web- and Portlet-related ApplicationContexts override use of the
    DefaultEnvironment and swap in DefaultWebEnvironment or
    DefaultPortletEnvironment as appropriate.

Introduced "stub-and-replace" behavior for Servlet- and Portlet-based
PropertySource implementations

    Allows for early registration and ordering of the stub, then
    replacement with actual backing object at refresh() time.

    Added AbstractApplicationContext.initPropertySources() method to
    support stub-and-replace behavior. Called from within existing
    prepareRefresh() method so as to avoid impact with
    ApplicationContext implementations that copy and modify AAC's
    refresh() method (e.g.: Spring DM).

    Added methods to WebApplicationContextUtils and
    PortletApplicationContextUtils to support stub-and-replace behavior

Added comprehensive Javadoc for all new or modified types and members

Added XSD documentation for all new or modified elements and attributes

    Including nested <beans>, <beans profile="..."/>, and changes for
    certain attributes type from xsd:IDREF to xsd:string

Improved fix for detecting non-file based Resources in
PropertiesLoaderSupport (SPR-7547, SPR-7552)

    Technically unrelated to environment work, but grouped in with
    this changeset for convenience.

Deprecated (removed) context:property-placeholder
'system-properties-mode' attribute from spring-context-3.1.xsd

    Functionality is preserved for those using schemas up to and including
    spring-context-3.0.  For 3.1, system-properties-mode is no longer
    supported as it conflicts with the idea of managing a set of property
    sources within the context's Environment object. See Javadoc in
    PropertyPlaceholderConfigurer, AbstractPropertyPlaceholderConfigurer
    and PropertySourcesPlaceholderConfigurer for details.

Introduced CollectionUtils.toArray(Enumeration<E>, A[])

Work items remaining for 3.1 M2:

    Consider repackaging PropertySource* types; eliminate internal use
    of SystemPropertyUtils and deprecate

    Further work on composition of Environment interface; consider
    repurposing existing PlaceholderResolver interface to obviate need
    for resolve[Required]Placeholder() methods currently in Environment.

    Ensure configurability of placeholder prefix, suffix, and value
    separator when working against an AbstractPropertyResolver

    Add JNDI-based Environment / PropertySource implementatinos

    Consider support for @Profile at the @Bean level

    Provide consistent logging for the entire property resolution
    lifecycle; consider issuing all such messages against a dedicated
    logger with a single category.

    Add reference documentation to cover the featureset.
This commit is contained in:
Chris Beams
2011-01-03 09:04:34 +00:00
parent b130a36af7
commit b3ff9be78f
111 changed files with 3439 additions and 1715 deletions

View File

@@ -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.
@@ -96,12 +96,13 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life
void setParent(ApplicationContext parent);
/**
* TODO SPR-7508: document
* Return the Environment for this application context in configurable form.
*/
ConfigurableEnvironment getEnvironment();
/**
* TODO SPR-7508: document
* Set the {@code Environment} for this application context.
* @param environment the new environment
*/
void setEnvironment(ConfigurableEnvironment environment);

View File

@@ -19,12 +19,17 @@ package org.springframework.context;
import org.springframework.core.env.Environment;
/**
* TODO SPR-7515: document
* Interface to be implemented by any bean that wishes to be notified
* of the {@link Environment} that it runs in.
*
* @author Chris Beams
* @since 3.1
*/
public interface EnvironmentAware {
/**
* Set the {@code Environment} that this object runs in.
*/
void setEnvironment(Environment environment);
}

View File

@@ -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.
@@ -50,9 +50,9 @@ public class AnnotatedBeanDefinitionReader {
/**
* Create a new AnnotatedBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
* Create a new {@code AnnotatedBeanDefinitionReader} for the given bean factory.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this.registry = registry;
@@ -68,8 +68,10 @@ public class AnnotatedBeanDefinitionReader {
}
/**
* Set the Environment to use when registering classes.
* Set the Environment to use when evaluating whether
* {@link Profile @Profile}-annotated component classes should be registered.
* <p>The default is a {@link DefaultEnvironment}.
* @see #registerBean(Class, String, Class...)
*/
public void setEnvironment(Environment environment) {
this.environment = environment;
@@ -80,7 +82,8 @@ public class AnnotatedBeanDefinitionReader {
* <p>The default is a {@link AnnotationBeanNameGenerator}.
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
this.beanNameGenerator = (beanNameGenerator != null ?
beanNameGenerator : new AnnotationBeanNameGenerator());
}
/**
@@ -88,7 +91,8 @@ public class AnnotatedBeanDefinitionReader {
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
*/
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
this.scopeMetadataResolver = (scopeMetadataResolver != null ?
scopeMetadataResolver : new AnnotationScopeMetadataResolver());
}
@@ -110,10 +114,8 @@ public class AnnotatedBeanDefinitionReader {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
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)) {
if (Profile.Helper.isProfileAnnotationPresent(metadata)) {
if (!this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata))) {
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
return;
}

View File

@@ -16,17 +16,15 @@
package org.springframework.context.annotation;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
/**
* Standalone application context, accepting annotated classes as input - in particular
* {@link org.springframework.context.annotation.Configuration @Configuration}-annotated
* classes, but also plain {@link org.springframework.stereotype.Component @Components}
* and JSR-330 compliant classes using {@literal javax.inject} annotations. Allows for
* and JSR-330 compliant classes using {@code javax.inject} annotations. Allows for
* registering classes one by one ({@link #register}) as well as for classpath scanning
* ({@link #scan}).
*
@@ -49,15 +47,13 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this);
{ // TODO: rework this, it's a bit confusing
this.setEnvironment(this.getEnvironment());
}
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@link #refresh refreshed}.
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
this.delegateEnvironment(super.getEnvironment());
}
/**
@@ -67,6 +63,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
@@ -77,16 +74,24 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
* @param basePackages the packages to check for annotated classes
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
/**
* TODO SPR-7508: document
* {@inheritDoc}
* <p>Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader}
* and {@link ClassPathBeanDefinitionScanner} members.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
delegateEnvironment(environment);
}
private void delegateEnvironment(ConfigurableEnvironment environment) {
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}

View File

@@ -27,11 +27,11 @@ import org.springframework.beans.factory.annotation.Autowire;
/**
* Indicates that a method produces a bean to be managed by the Spring container. The
* names and semantics of the attributes to this annotation are intentionally similar
* to those of the {@literal <bean/>} element in the Spring XML schema.
* to those of the {@code <bean/>} element in the Spring XML schema.
*
* <p>Note that the <code>@Bean</code> annotation does not provide attributes for scope,
* primary or lazy. Rather, it should be used in conjunction with {@link Scope &#064;Scope},
* {@link Primary &#064;Primary}, and {@link Lazy &#064;Lazy} annotations to achieve
* <p>Note that the {@code @Bean} annotation does not provide attributes for scope,
* primary or lazy. Rather, it should be used in conjunction with {@link Scope @Scope},
* {@link Primary @Primary}, and {@link Lazy @Lazy} annotations to achieve
* those semantics. The same annotations can also be used at the type level, e.g. for
* component scanning.
*
@@ -96,7 +96,7 @@ public @interface Bean {
/**
* The optional name of a method to call on the bean instance upon closing the
* application context, for example a {@literal close()} method on a {@literal DataSource}.
* application context, for example a {@code close()} method on a {@code DataSource}.
* The method must have no arguments but may throw any exception.
* <p>Note: Only invoked on beans whose lifecycle is under the full control of the
* factory, which is always the case for singletons but not guaranteed

View File

@@ -116,15 +116,15 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
}
/**
* TODO SPR-7508: document
* Set the Environment to use when resolving placeholders and evaluating
* {@link Profile @Profile}-annotated component classes.
* <p>The default is a {@link DefaultEnvironment}
* @param environment the Environment to use
*/
public void setEnvironment(Environment environment) {
this.environment = environment;
}
/**
* TODO SPR-7508: document
*/
public Environment getEnvironment() {
return this.environment;
}
@@ -280,7 +280,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
* @return the pattern specification to be used for package searching
*/
protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(basePackage));
return ClassUtils.convertClassNameToResourcePath(environment.getPropertyResolver().resolveRequiredPlaceholders(basePackage));
}
/**
@@ -298,12 +298,11 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
if (!metadata.hasAnnotation(Profile.class.getName())) {
if (!Profile.Helper.isProfileAnnotationPresent(metadata)) {
return true;
}
String[] specifiedProfiles =
(String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
return this.environment.acceptsProfiles(specifiedProfiles);
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
return this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata));
}
}
return false;

View File

@@ -27,7 +27,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
/**
* Configures component scanning directives for use with {@link Configuration}
* classes. Provides support parallel with Spring XML's
* &lt;context:component-scan&gt; element.
* {@code <context:component-scan>} element.
*
* TODO SPR-7508: complete documentation.
*

View File

@@ -101,16 +101,14 @@ class ConfigurationClassParser {
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
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)) {
AnnotationMetadata metadata = configClass.getMetadata();
if (this.environment != null && Profile.Helper.isProfileAnnotationPresent(metadata)) {
if (!this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata))) {
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
return;
}
}
AnnotationMetadata metadata = configClass.getMetadata();
while (metadata != null) {
doProcessConfigurationClass(configClass, metadata);
String superClassName = metadata.getSuperClassName();

View File

@@ -49,8 +49,8 @@ import org.springframework.util.ClassUtils;
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
* {@link Configuration @Configuration} classes.
*
* <p>Registered by default when using {@literal <context:annotation-config/>} or
* {@literal <context:component-scan/>}. Otherwise, may be declared manually as
* <p>Registered by default when using {@code <context:annotation-config/>} or
* {@code <context:component-scan/>}. Otherwise, may be declared manually as
* with any other BeanFactoryPostProcessor.
*
* <p>This post processor is {@link Ordered#HIGHEST_PRECEDENCE} as it is important
@@ -100,7 +100,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
/**
* Set the {@link ProblemReporter} to use.
* <p>Used to register any problems detected with {@link Configuration} or {@link Bean}
* declarations. For instance, an @Bean method marked as {@literal final} is illegal
* declarations. For instance, an @Bean method marked as {@code final} is illegal
* and would be reported as a problem. Defaults to {@link FailFastProblemReporter}.
*/
public void setProblemReporter(ProblemReporter problemReporter) {
@@ -110,7 +110,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
/**
* Set the {@link MetadataReaderFactory} to use.
* <p>Default is a {@link CachingMetadataReaderFactory} for the specified
* {@link #setBeanClassLoader bean class loader}.
* {@linkplain #setBeanClassLoader bean class loader}.
*/
public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");

View File

@@ -38,7 +38,7 @@ import java.lang.annotation.Documented;
* <p>Using {@link DependsOn} at the class level has no effect unless component-scanning
* is being used. If a {@link DependsOn}-annotated class is declared via XML,
* {@link DependsOn} annotation metadata is ignored, and
* {@literal <bean depends-on="..."/>} is respected instead.
* {@code <bean depends-on="..."/>} is respected instead.
*
* @author Juergen Hoeller
* @since 3.0

View File

@@ -23,18 +23,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates one or more {@link Configuration} classes to import.
* Indicates one or more {@link Configuration @Configuration} classes to import.
*
* <p>Provides functionality equivalent to the {@literal <import/>} element in Spring XML.
* Only supported for actual {@literal @Configuration}-annotated classes.
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Only supported for actual {@code @Configuration}-annotated classes.
*
* <p>{@literal @Bean} definitions declared in imported {@literal @Configuration} classes
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes
* should be accessed by using {@link Autowired @Autowired} injection. Either the bean
* itself can be autowired, or the configuration class instance declaring the bean can be
* autowired. The latter approach allows for explicit, IDE-friendly navigation between
* {@literal @Configuration} class methods.
* {@code @Configuration} class methods.
*
* <p>If XML or other non-{@literal @Configuration} bean definition resources need to be
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use {@link ImportResource @ImportResource}
*
* @author Chris Beams

View File

@@ -30,14 +30,14 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
* Indicates one or more resources containing bean definitions to import.
*
* <p>Like {@link Import @Import}, this annotation provides functionality similar to the
* {@literal <import/>} element in Spring XML. It is typically used when
* {@code <import/>} element in Spring XML. It is typically used when
* designing {@link Configuration @Configuration} classes to be bootstrapped by
* {@link AnnotationConfigApplicationContext}, but where some XML functionality such as
* namespaces is still necessary.
*
* <p>By default, arguments to the {@link #value()} attribute will be processed using
* an {@link XmlBeanDefinitionReader}, i.e. it is assumed that resources are Spring
* {@literal <beans/>} XML files. Optionally, the {@link #reader()} attribute may be
* {@code <beans/>} XML files. Optionally, the {@link #reader()} attribute may be
* supplied, allowing the user to specify a different {@link BeanDefinitionReader}
* implementation, such as
* {@link org.springframework.beans.factory.support.PropertiesBeanDefinitionReader}.
@@ -53,8 +53,8 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
public @interface ImportResource {
/**
* Resource paths to import. Resource-loading prefixes such as {@literal classpath:} and
* {@literal file:}, etc may be used.
* Resource paths to import. Resource-loading prefixes such as {@code classpath:} and
* {@code file:}, etc may be used.
*/
String[] value();

View File

@@ -25,25 +25,25 @@ import java.lang.annotation.Inherited;
/**
* Indicates whether a bean is to be lazily initialized.
*
*
* <p>May be used on any class directly or indirectly annotated with
* {@link org.springframework.stereotype.Component} or on methods annotated with
* {@link Bean}.
*
*
* <p>If this annotation is not present on a Component or Bean definition, eager
* initialization will occur. If present and set to {@literal true}, the
* initialization will occur. If present and set to {@code true}, the
* Bean/Component will not be initialized until referenced by another bean or
* explicitly retrieved from the enclosing
* {@link org.springframework.beans.factory.BeanFactory}. If present and set to
* {@literal false}, the bean will be instantiated on startup by bean factories
* {@code false}, the bean will be instantiated on startup by bean factories
* that perform eager initialization of singletons.
*
* <p>If Lazy is present on a {@link Configuration} class, this indicates that all
* {@link Bean} methods within that {@literal Configuration} should be lazily
* initialized. If Lazy is present and false on a Bean method within a
* Lazy-annotated Configuration class, this indicates overriding the 'default
* lazy' behavior and that the bean should be eagerly initialized.
*
*
* <p>If Lazy is present on a {@link Configuration @Configuration} class, this
* indicates that all {@link Bean @Bean} methods within that {@code @Configuration}
* should be lazily initialized. If Lazy is present and false on a Bean method
* within a Lazy-annotated Configuration class, this indicates overriding the
* 'default lazy' behavior and that the bean should be eagerly initialized.
*
* @author Chris Beams
* @since 3.0
* @see Primary

View File

@@ -27,16 +27,16 @@ import java.lang.annotation.Target;
* Indicates that a bean should be given preference when multiple candidates
* are qualified to autowire a single-valued dependency. If exactly one 'primary'
* bean exists among the candidates, it will be the autowired value.
*
*
* <p>May be used on any class directly or indirectly annotated with
* {@link org.springframework.stereotype.Component} or on methods annotated
* with {@link Bean}.
*
*
* <p>Using {@link Primary} at the class level has no effect unless component-scanning
* is being used. If a {@link Primary}-annotated class is declared via XML,
* {@link Primary} annotation metadata is ignored, and
* {@literal <bean primary="true|false"/>} is respected instead.
*
* {@code <bean primary="true|false"/>} is respected instead.
*
* @author Chris Beams
* @since 3.0
* @see Lazy

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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,42 +16,78 @@
package org.springframework.context.annotation;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.type.AnnotationMetadata;
/**
* TODO SPR-7508: document
*
* Components not @Profile-annotated will always be registered
* 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
* Indicates that a component is eligible for registration when one or more {@linkplain #value
* specified profiles} are active.
*
* <p>A <em>profile</em> is a named logical grouping that may be activated programatically via
* {@link ConfigurableEnvironment#setActiveProfiles} or declaratively through setting the
* {@link AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME spring.profile.active} property,
* usually through JVM system properties, as an environment variable, or for web applications
* as a Servlet context parameter in {@code web.xml}.
*
* <p>The {@code @Profile} annotation may be used in any of the following ways:
* <ul>
* <li>as a type-level annotation on any class directly or indirectly annotated with
* {@code @Component}, including {@link Configuration @Configuration} classes
* <li>as a meta-annotation, for the purpose of composing custom stereotype annotations
* </ul>
*
* <p>If a {@code @Configuration} class is marked with {@code @Profile}, all of the
* {@code @Bean} methods and {@link Import @Import} annotations associated with that class will
* be bypassed unless one or more the specified profiles are active. This is very similar to
* the behavior in Spring XML: if the {@code profile} attribute of the {@code beans} element is
* supplied e.g., {@code <beans profile="p1,p2">}, the {@code beans} element will not be parsed unless
* profiles 'p1' and/or 'p2' have been activated. Likewise, if a {@code @Component} or
* {@code @Configuration} class is marked with <code>@Profile({"p1", "p2"})</code>, that class will
* not be registered/processed unless profiles 'p1' and/or 'p2' have been activated.
*
* <p>If the {@code @Profile} annotation is omitted, registration will occur, regardless of which,
* if any, profiles are active.
*
* <p>When defining Spring beans via XML, the {@code "profile"} attribute of the {@code <beans>}
* element may be used. See the documentation in {@code spring-beans-3.1.xsd} for details.
*
* @author Chris Beams
* @since 3.1
* @see ConfigurableEnvironment#setActiveProfiles
* @see ConfigurableEnvironment#setDefaultProfiles
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({
ANNOTATION_TYPE, // @Profile may be used as a meta-annotation
TYPE // In conjunction with @Component and its derivatives
})
@Target(ElementType.TYPE)
public @interface Profile {
/**
* @see #value()
*/
static final String CANDIDATE_PROFILES_ATTRIB_NAME = "value";
/**
* TODO SPR-7508: document
* The set profiles for which this component should be registered.
*/
String[] value();
static class Helper {
/**
* Return whether the given metadata includes Profile information, whether directly or
* through meta-annotation.
*/
static boolean isProfileAnnotationPresent(AnnotationMetadata metadata) {
return metadata.isAnnotated(Profile.class.getName());
}
/**
* Return the String[] of candidate profiles from {@link Profile#value()}.
*/
static String[] getCandidateProfiles(AnnotationMetadata metadata) {
return (String[])metadata.getAnnotationAttributes(Profile.class.getName()).get("value");
}
}
}

View File

@@ -35,7 +35,7 @@ import org.springframework.stereotype.Component;
* the instance returned from the method.
*
* <p>In this context, scope means the lifecycle of an instance, such as
* {@literal singleton}, {@literal prototype}, and so forth.
* {@code singleton}, {@code prototype}, and so forth.
*
* @author Mark Fisher
* @author Chris Beams
@@ -59,7 +59,7 @@ public @interface Scope {
* and if so, whether the proxy should be interface-based or subclass-based.
* <p>Defaults to {@link ScopedProxyMode#NO}, indicating that no scoped
* proxy should be created.
* <p>Analogous to {@literal <aop:scoped-proxy/>} support in Spring XML.
* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

View File

@@ -1,10 +1,10 @@
/**
*
*
* Annotation support for the Application Context, including JSR-250 "common"
* annotations, component-scanning, and Java-based metadata for creating
* Spring-managed objects.
*
*
*/
package org.springframework.context.annotation;

View File

@@ -20,7 +20,7 @@ import org.w3c.dom.Element;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.EnvironmentAwarePropertyPlaceholderConfigurer;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.util.StringUtils;
/**
@@ -35,32 +35,24 @@ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBea
@Override
protected Class<?> getBeanClass(Element element) {
// as of Spring 3.1, the default for system-properties-mode is DELEGATE,
// meaning that the attribute should be disregarded entirely, instead
// deferring to the order of PropertySource objects in the enclosing
// application context's Environment object
if (!"DELEGATE".equals(element.getAttribute("system-properties-mode"))) {
if (element.hasAttribute("system-properties-mode")) {
return PropertyPlaceholderConfigurer.class;
}
return EnvironmentAwarePropertyPlaceholderConfigurer.class;
return PropertySourcesPlaceholderConfigurer.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
if (!"DELEGATE".equals(element.getAttribute("system-properties-mode"))) {
String systemPropertiesModeName = element.getAttribute("system-properties-mode");
if (StringUtils.hasLength(systemPropertiesModeName)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
}
String systemPropertiesModeName = element.getAttribute("system-properties-mode");
if (StringUtils.hasLength(systemPropertiesModeName)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
}
}
}

View File

@@ -44,11 +44,11 @@ public class EnvironmentAccessor implements PropertyAccessor {
}
/**
* Access provided {@literal target} object by calling its {@link Environment#getProperty(String)}
* method with the provided {@literal name}.
* Access the given target object by resolving the given property name against the given target
* environment.
*/
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(((Environment)target).getProperty(name));
return new TypedValue(((Environment)target).getPropertyResolver().getProperty(name));
}
/**

View File

@@ -206,8 +206,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/** Statically specified listeners */
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/** TODO SPR-7508: document */
private ConfigurableEnvironment environment = new DefaultEnvironment();
/** Environment used by this context; initialized by {@link #createEnvironment()} */
private ConfigurableEnvironment environment;
/**
@@ -224,6 +224,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
public AbstractApplicationContext(ApplicationContext parent) {
this.parent = parent;
this.resourcePatternResolver = getResourcePatternResolver();
this.environment = this.createEnvironment();
}
@@ -279,6 +280,14 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return this.environment;
}
/**
* {@inheritDoc}
* <p>Default value is determined by {@link #createEnvironment()}. Replacing the
* default with this method is one option but configuration through {@link
* #getEnvironment()} should also be considered. In either case, such modifications
* should be performed <em>before</em> {@link #refresh()}.
* @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
*/
public void setEnvironment(ConfigurableEnvironment environment) {
this.environment = environment;
}
@@ -400,6 +409,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return this.applicationListeners;
}
/**
* Create and return a new {@link DefaultEnvironment}.
*/
protected ConfigurableEnvironment createEnvironment() {
return new DefaultEnvironment();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
@@ -456,7 +471,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/**
* Prepare this context for refreshing, setting its startup date and
* active flag.
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
@@ -468,6 +483,18 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
}
/**
* <p>Replace any stub property sources with actual instances.
* @see org.springframework.core.env.PropertySource.StubPropertySource
* @see org.springframework.web.context.support.WebApplicationContextUtils#initSerlvetPropertySources
*/
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
/**

View File

@@ -28,7 +28,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
/**
* Base class for {@link org.springframework.context.ApplicationContext}
* implementations which are supposed to support multiple calls to {@literal refresh},
* implementations which are supposed to support multiple calls to {@link #refresh()},
* creating a new internal bean factory instance every time.
* Typically (but not necessarily), such a context will be driven by
* a set of config locations to load bean definitions from.
@@ -50,7 +50,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
* and {@link FileSystemXmlApplicationContext}, which both derive from the
* common {@link AbstractXmlApplicationContext} base class;
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
* supports {@literal @Configuration}-annotated classes as a source of bean definitions.
* supports {@code @Configuration}-annotated classes as a source of bean definitions.
*
* @author Juergen Hoeller
* @author Chris Beams
@@ -182,7 +182,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
* Called for each {@link #refresh()} attempt.
* <p>The default implementation creates a
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* with the {@link #getInternalParentBeanFactory() internal bean factory} of this
* with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this
* context's parent as parent bean factory. Can be overridden in subclasses,
* for example to customize DefaultListableBeanFactory's settings.
* @return the bean factory for this context
@@ -199,8 +199,8 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
* Customize the internal bean factory used by this context.
* Called for each {@link #refresh()} attempt.
* <p>The default implementation applies this context's
* {@link #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@link #setAllowCircularReferences "allowCircularReferences"} settings,
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
* if specified. Can be overridden in subclasses to customize any of
* {@link DefaultListableBeanFactory}'s settings.
* @param beanFactory the newly created bean factory for this context

View File

@@ -17,11 +17,11 @@
package org.springframework.context.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.SystemPropertyUtils;
/**
* {@link AbstractRefreshableApplicationContext} subclass that adds common handling
@@ -117,14 +117,9 @@ public abstract class AbstractRefreshableConfigApplicationContext extends Abstra
* system property values if necessary. Applied to config locations.
* @param path the original file path
* @return the resolved file path
* @see SystemPropertyUtils#resolveRequiredPlaceholders(String)
*/
protected String resolvePath(String path) {
// TODO SPR-7508: note that ARAC cannot delegate to its beanFactory's environment
// to call Environment.resolve[Required]Placeholders(String), as the bean factory
// has not yet been initialized. This amounts to one more reason not to use the ARAC
// hierarchy - it won't have early access to environment property resolution.
return SystemPropertyUtils.resolvePlaceholders(path);
return this.getEnvironment().getPropertyResolver().resolveRequiredPlaceholders(path);
}

View File

@@ -1,115 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.support;
import java.util.LinkedList;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AbstractPropertyPlaceholderConfigurer;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
/**
* TODO SPR-7508: document
*
* Local properties are added as a property source in any case. Precedence is based
* on the value of the {@link #setLocalOverride(boolean) localOverride} property.
*
* @author Chris Beams
* @since 3.1
* @see PropertyPlaceholderConfigurer
* @see EnvironmentAwarePropertyOverrideConfigurer
*/
public class EnvironmentAwarePropertyPlaceholderConfigurer
extends AbstractPropertyPlaceholderConfigurer implements EnvironmentAware {
private ConfigurableEnvironment environment;
private Environment wrappedEnvironment;
public void setEnvironment(Environment environment) {
this.wrappedEnvironment = environment;
}
@Override
protected PlaceholderResolver getPlaceholderResolver(Properties props) {
return new PlaceholderResolver() {
public String resolvePlaceholder(String placeholderName) {
return environment.getProperty(placeholderName);
}
};
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Assert.notNull(this.wrappedEnvironment, "Environment must not be null. Did you call setEnvironment()?");
environment = new AbstractEnvironment() { };
LinkedList<PropertySource<?>> propertySources = environment.getPropertySources();
EnvironmentPropertySource environmentPropertySource =
new EnvironmentPropertySource("wrappedEnvironment", wrappedEnvironment);
if (!this.localOverride) {
propertySources.add(environmentPropertySource);
}
if (this.localProperties != null) {
int cx=0;
for (Properties localProps : this.localProperties) {
propertySources.add(new PropertiesPropertySource("localProperties"+cx++, localProps));
}
}
if (this.localOverride) {
propertySources.add(environmentPropertySource);
}
super.postProcessBeanFactory(beanFactory);
}
static class EnvironmentPropertySource extends PropertySource<Environment> {
public EnvironmentPropertySource(String name, Environment source) {
super(name, source);
}
@Override
public boolean containsProperty(String key) {
return source.containsProperty(key);
}
@Override
public String getProperty(String key) {
return source.getProperty(key);
}
@Override
public int size() {
// TODO Auto-generated method stub
return source.getPropertyCount();
}
}
}

View File

@@ -28,7 +28,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;

View File

@@ -44,8 +44,8 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
/**
* Create a new GenericXmlApplicationContext that needs to be populated
* through {@link #load} calls and then manually {@link #refresh refreshed}.
* Create a new GenericXmlApplicationContext that needs to be
* {@linkplain #load loaded} and then manually {@link #refresh refreshed}.
*/
public GenericXmlApplicationContext() {
reader.setEnvironment(this.getEnvironment());
@@ -91,8 +91,9 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
}
/**
* Set a custom environment. Should be called before any call to
* {@link #load}. TODO SPR-7508: document
* {@inheritDoc}
* <p>Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
* Should be called before any call to {@link #load}.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {

View File

@@ -0,0 +1,134 @@
/*
* Copyright 2002-2011 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.support;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.AbstractPropertyPlaceholderConfigurer;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
/**
* Specialization of {@link AbstractPropertyPlaceholderConfigurer}
*
* <p>Local properties are added as a property source in any case. Precedence is based
* on the value of the {@link #setLocalOverride localOverride} property.
*
* @author Chris Beams
* @since 3.1
* @see AbstractPropertyPlaceholderConfigurer
* @see PropertyPlaceholderConfigurer
*/
public class PropertySourcesPlaceholderConfigurer extends AbstractPropertyPlaceholderConfigurer
implements EnvironmentAware {
/**
* {@value} is the name given to the {@link PropertySource} for the set of
* {@linkplain #mergeProperties() merged properties} supplied to this configurer.
*/
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
private MutablePropertySources propertySources;
private PropertyResolver propertyResolver;
private Environment environment;
/**
* {@inheritDoc}
* <p>{@code PropertySources} from this environment will be searched when replacing ${...} placeholders
* @see #setPropertySources
* @see #postProcessBeanFactory
*/
public void setEnvironment(Environment environment) {
this.environment = environment;
}
/**
* Customize the set of {@link PropertySources} to be used by this configurer.
* Setting this property indicates that environment property sources and local
* properties should be ignored.
* @see #postProcessBeanFactory
*/
public void setPropertySources(PropertySources propertySources) {
this.propertySources = new MutablePropertySources(propertySources);
}
@Override
protected PlaceholderResolver getPlaceholderResolver(Properties props) {
return new PlaceholderResolver() {
public String resolvePlaceholder(String placeholderName) {
return propertyResolver.getProperty(placeholderName);
}
};
}
/**
* {@inheritDoc}
* <p>Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
* against this configurer's set of {@link PropertySources}, which includes:
* <ul>
* <li>all {@linkplain Environment#getPropertySources environment property sources}, if an
* {@code Environment} {@linkplain #setEnvironment is present}
* <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any}
* {@linkplain #setLocations have} {@linkplain #setProperties been}
* {@linkplain #setPropertiesArray specified}
* <li>any property sources set by calling {@link #setPropertySources}
* </ul>
* <p>If {@link #setPropertySources} is called, <strong>environment and local properties will be
* ignored</strong>. This method is designed to give the user fine-grained control over property
* sources, and once set, the configurer makes no assumptions about adding additional sources.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addAll(this.environment.getPropertySources());
}
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, this.mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
} else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
this.processProperties(beanFactory, this.propertyResolver.asProperties());
}
}

View File

@@ -30,8 +30,6 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.DefaultEnvironment;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.jndi.TypeMismatchNamingException;
@@ -70,9 +68,6 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
/** Cache of the types of nonshareable resources: bean name --> bean type */
private final Map<String, Class> resourceTypes = new HashMap<String, Class>();
/** TODO SPR-7508: should be JNDI-specific environment */
private ConfigurableEnvironment environment = new DefaultEnvironment();
public SimpleJndiBeanFactory() {
setResourceRef(true);