Consistent Environment access in XML bean definition parsing code

Issue: SPR-12248
This commit is contained in:
Juergen Hoeller 2014-09-25 01:02:40 +02:00
parent b0e6091cad
commit 5ecdd8ca31
8 changed files with 53 additions and 62 deletions

View File

@ -671,7 +671,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
private GroovyDynamicElementReader createDynamicElementReader(String namespace) { private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
XmlReaderContext readerContext = this.xmlBeanDefinitionReader.createReaderContext(new DescriptiveResource("Groovy")); XmlReaderContext readerContext = this.xmlBeanDefinitionReader.createReaderContext(new DescriptiveResource("Groovy"));
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, getEnvironment()); BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
boolean decorating = (this.currentBeanDefinition != null); boolean decorating = (this.currentBeanDefinition != null);
if (!decorating) { if (!decorating) {
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(namespace); this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(namespace);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,7 +41,9 @@ public interface BeanDefinitionDocumentReader {
* Set the Environment to use when reading bean definitions. * Set the Environment to use when reading bean definitions.
* <p>Used for evaluating profile information to determine whether a * <p>Used for evaluating profile information to determine whether a
* {@code <beans/>} document/element should be included or ignored. * {@code <beans/>} document/element should be included or ignored.
* @deprecated in favor of {@link XmlReaderContext#getEnvironment()}
*/ */
@Deprecated
void setEnvironment(Environment environment); void setEnvironment(Environment environment);
/** /**

View File

@ -59,7 +59,6 @@ import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.support.MethodOverrides; import org.springframework.beans.factory.support.MethodOverrides;
import org.springframework.beans.factory.support.ReplaceOverride; import org.springframework.beans.factory.support.ReplaceOverride;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -246,8 +245,6 @@ public class BeanDefinitionParserDelegate {
private final XmlReaderContext readerContext; private final XmlReaderContext readerContext;
private final Environment environment;
private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition(); private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
private final ParseState parseState = new ParseState(); private final ParseState parseState = new ParseState();
@ -261,25 +258,23 @@ public class BeanDefinitionParserDelegate {
/** /**
* Create a new BeanDefinitionParserDelegate associated with the * Create a new BeanDefinitionParserDelegate associated with the supplied
* supplied {@link XmlReaderContext} and {@link Environment}. * {@link XmlReaderContext}.
*/ */
public BeanDefinitionParserDelegate(XmlReaderContext readerContext, Environment environment) { public BeanDefinitionParserDelegate(XmlReaderContext readerContext) {
Assert.notNull(readerContext, "XmlReaderContext must not be null"); Assert.notNull(readerContext, "XmlReaderContext must not be null");
Assert.notNull(environment, "Environment must not be null");
this.readerContext = readerContext; this.readerContext = readerContext;
this.environment = environment;
} }
/** /**
* Create a new BeanDefinitionParserDelegate associated with the * Create a new BeanDefinitionParserDelegate associated with the supplied
* supplied {@link XmlReaderContext} and a new {@link StandardEnvironment}. * {@link XmlReaderContext}.
* @deprecated since Spring 3.1 in favor of * @deprecated since the given {@link Environment} parameter is effectively
* {@link #BeanDefinitionParserDelegate(XmlReaderContext, Environment)} * ignored in favor of {@link XmlReaderContext#getEnvironment()}
*/ */
@Deprecated @Deprecated
public BeanDefinitionParserDelegate(XmlReaderContext readerContext) { public BeanDefinitionParserDelegate(XmlReaderContext readerContext, Environment environment) {
this(readerContext, new StandardEnvironment()); this(readerContext);
} }
@ -292,9 +287,11 @@ public class BeanDefinitionParserDelegate {
/** /**
* Get the {@link Environment} associated with this helper instance. * Get the {@link Environment} associated with this helper instance.
* @deprecated in favor of {@link XmlReaderContext#getEnvironment()}
*/ */
@Deprecated
public final Environment getEnvironment() { public final Environment getEnvironment() {
return this.environment; return this.readerContext.getEnvironment();
} }
/** /**

View File

@ -35,7 +35,6 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -77,27 +76,18 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
private Environment environment;
private XmlReaderContext readerContext; private XmlReaderContext readerContext;
private BeanDefinitionParserDelegate delegate; private BeanDefinitionParserDelegate delegate;
/** @Deprecated
* {@inheritDoc}
* <p>Default value is {@code null}; property is required for parsing any
* {@code <beans/>} element with a {@code profile} attribute present.
* @see #doRegisterBeanDefinitions
*/
@Override @Override
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
this.environment = environment;
} }
/** /**
* {@inheritDoc} * This implementation parses bean definitions according to the "spring-beans" XSD
* <p>This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically). * (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings * <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions. * specified at the {@code <beans/>} level; then parses the contained bean definitions.
@ -110,12 +100,24 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
doRegisterBeanDefinitions(root); doRegisterBeanDefinitions(root);
} }
/**
* Return the descriptor for the XML resource that this parser works on.
*/
protected final XmlReaderContext getReaderContext() {
return this.readerContext;
}
/**
* Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the
* source metadata from the supplied {@link Element}.
*/
protected Object extractSource(Element ele) {
return getReaderContext().extractSource(ele);
}
/** /**
* Register each bean definition within the given root {@code <beans/>} element. * Register each bean definition within the given root {@code <beans/>} element.
* @throws IllegalStateException if {@code <beans profile="..."} attribute is present
* and Environment property has not been set
* @see #setEnvironment
*/ */
protected void doRegisterBeanDefinitions(Element root) { protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In // Any nested <beans> elements will cause recursion in this method. In
@ -125,15 +127,14 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
// then ultimately reset this.delegate back to its original (parent) reference. // then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one. // this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate; BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent); this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) { if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) { if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray( String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) { if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return; return;
} }
} }
@ -149,27 +150,11 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
protected BeanDefinitionParserDelegate createDelegate( protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, this.environment); BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate); delegate.initDefaults(root, parentDelegate);
return delegate; return delegate;
} }
/**
* Return the descriptor for the XML resource that this parser works on.
*/
protected final XmlReaderContext getReaderContext() {
return this.readerContext;
}
/**
* Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the
* source metadata from the supplied {@link Element}.
*/
protected Object extractSource(Element ele) {
return this.readerContext.extractSource(ele);
}
/** /**
* Parse the elements at the root level in the document: * Parse the elements at the root level in the document:
* "import", "alias", "bean". * "import", "alias", "bean".
@ -224,7 +209,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
} }
// Resolve system properties: e.g. "${user.dir}" // Resolve system properties: e.g. "${user.dir}"
location = environment.resolveRequiredPlaceholders(location); location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<Resource>(4); Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

View File

@ -135,6 +135,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
super(registry); super(registry);
} }
/** /**
* Set whether to use XML validation. Default is {@code true}. * Set whether to use XML validation. Default is {@code true}.
* <p>This method switches namespace awareness on if validation is turned off, * <p>This method switches namespace awareness on if validation is turned off,
@ -501,9 +502,10 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
* @see #setDocumentReaderClass * @see #setDocumentReaderClass
* @see BeanDefinitionDocumentReader#registerBeanDefinitions * @see BeanDefinitionDocumentReader#registerBeanDefinitions
*/ */
@SuppressWarnings("deprecation")
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment()); documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount(); int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore; return getRegistry().getBeanDefinitionCount() - countBefore;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.springframework.beans.factory.parsing.ReaderContext;
import org.springframework.beans.factory.parsing.ReaderEventListener; import org.springframework.beans.factory.parsing.ReaderEventListener;
import org.springframework.beans.factory.parsing.SourceExtractor; import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
@ -74,6 +75,10 @@ public class XmlReaderContext extends ReaderContext {
return this.reader.getBeanClassLoader(); return this.reader.getBeanClassLoader();
} }
public final Environment getEnvironment() {
return this.reader.getEnvironment();
}
public final NamespaceHandlerResolver getNamespaceHandlerResolver() { public final NamespaceHandlerResolver getNamespaceHandlerResolver() {
return this.namespaceHandlerResolver; return this.namespaceHandlerResolver;
} }

View File

@ -103,8 +103,7 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
* {@link org.springframework.stereotype.Component @Component}, * {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository}, * {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and * {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* annotations.
* @see #setResourceLoader * @see #setResourceLoader
* @see #setEnvironment * @see #setEnvironment
*/ */
@ -124,13 +123,12 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
* @param registry the {@code BeanFactory} to load bean definitions into, in the form * @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry} * of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the * @param useDefaultFilters whether to include the default filters for the
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata.
* {@link org.springframework.stereotype.Component @Component}, * {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository}, * {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and * {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* annotations. * @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @since 3.1 * @since 3.1
* @see #setResourceLoader * @see #setResourceLoader
*/ */

View File

@ -115,6 +115,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
if (useDefaultFilters) { if (useDefaultFilters) {
registerDefaultFilters(); registerDefaultFilters();
} }
Assert.notNull(environment, "Environment must not be null");
this.environment = environment; this.environment = environment;
} }
@ -161,10 +162,11 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
/** /**
* Set the Environment to use when resolving placeholders and evaluating * Set the Environment to use when resolving placeholders and evaluating
* {@link Conditional @Conditional}-annotated component classes. * {@link Conditional @Conditional}-annotated component classes.
* <p>The default is a {@link StandardEnvironment} * <p>The default is a {@link StandardEnvironment}.
* @param environment the Environment to use * @param environment the Environment to use
*/ */
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment; this.environment = environment;
this.conditionEvaluator = null; this.conditionEvaluator = null;
} }