reworked ConfigurationClass(Web)ApplicationContext into AnnotationConfig(Web)ApplicationContext; revised BeansException signatures
This commit is contained in:
parent
87b2f23692
commit
8a09c8e7da
|
|
@ -9,6 +9,8 @@ Changes in version 3.0.0.RC2 (2009-10-30)
|
|||
* updated to final versions of JSR-330 "javax.inject" and JSR-303 "javax.validation" APIs
|
||||
* full compliance with the JSR-330 TCK (i.e. full compliance with the final specification)
|
||||
* support for Hibernate Validator 4.0 GA (as the JSR-303 reference implementation)
|
||||
* added AnnotatedBeanDefinitionReader helper for programmatic registration of annotated classes
|
||||
* added AnnotationConfig(Web)ApplicationContext for convenient registration/scanning of classes
|
||||
* revised MethodParameter's annotation accessor methods
|
||||
* PathMatchingResourcePatternResolver leniently ignores non-existing root directories
|
||||
* DefaultConversionService understands "on"/"off", "yes"/"no", "1"/"0" as boolean values
|
||||
|
|
@ -21,6 +23,7 @@ Changes in version 3.0.0.RC2 (2009-10-30)
|
|||
* ContentNegotiatingViewResolver works with ignoreAcceptHeader and defaultContentType as well
|
||||
* re-introduced Struts 1.x support ("org.springframework.web.struts") in deprecated form
|
||||
* deprecated scheduling support for JDK 1.3 Timer ("org.springframework.scheduling.timer")
|
||||
* deprecated remoting support for JAX-RPC (in favor of JAX-WS)
|
||||
|
||||
|
||||
Changes in version 3.0.0.RC1 (2009-09-25)
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
//---------------------------------------------------------------------
|
||||
|
||||
public <T> T getBean(Class<T> requiredType) throws BeansException {
|
||||
Assert.notNull(requiredType, "Required type must not be null");
|
||||
String[] beanNames = getBeanNamesForType(requiredType);
|
||||
if (beanNames.length == 1) {
|
||||
return getBean(beanNames[0], requiredType);
|
||||
|
|
@ -251,7 +252,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
return getParentBeanFactory().getBean(requiredType);
|
||||
}
|
||||
else {
|
||||
throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " + beanNames.length);
|
||||
throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " +
|
||||
beanNames.length + ": " + StringUtils.arrayToCommaDelimitedString(beanNames));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
|
|||
|
||||
/**
|
||||
* Convenient adapter for programmatic registration of annotated bean classes.
|
||||
*
|
||||
* This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
|
||||
* the same resolution of annotations but for explicitly registered classes only.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see AnnotationConfigApplicationContext#register
|
||||
*/
|
||||
public class AnnotatedBeanDefinitionReader {
|
||||
|
||||
|
|
@ -40,11 +42,15 @@ public class AnnotatedBeanDefinitionReader {
|
|||
|
||||
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
|
||||
|
||||
private boolean includeAnnotationConfig = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AnnotatedBeanDefinitionReader for the given bean factory.
|
||||
* @param registry the BeanFactory to load bean definitions into,
|
||||
* in the form of a BeanDefinitionRegistry
|
||||
*/
|
||||
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
|
||||
this.registry = registry;
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -65,35 +71,14 @@ public class AnnotatedBeanDefinitionReader {
|
|||
|
||||
/**
|
||||
* Set the ScopeMetadataResolver to use for detected bean classes.
|
||||
* Note that this will override any custom "scopedProxyMode" setting.
|
||||
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
* @see #setScopedProxyMode
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = scopeMetadataResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the proxy behavior for non-singleton scoped beans.
|
||||
* Note that this will override any custom "scopeMetadataResolver" setting.
|
||||
* <p>The default is {@link ScopedProxyMode#NO}.
|
||||
* @see #setScopeMetadataResolver
|
||||
*/
|
||||
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
|
||||
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to register annotation config post-processors.
|
||||
* <p>The default is to register the post-processors. Turn this off
|
||||
* to be able to ignore the annotations or to process them differently.
|
||||
*/
|
||||
public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
|
||||
this.includeAnnotationConfig = includeAnnotationConfig;
|
||||
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
|
||||
}
|
||||
|
||||
|
||||
public void registerBeans(Class<?>... annotatedClasses) {
|
||||
public void register(Class<?>... annotatedClasses) {
|
||||
for (Class<?> annotatedClass : annotatedClasses) {
|
||||
registerBean(annotatedClass);
|
||||
}
|
||||
|
|
@ -112,17 +97,7 @@ public class AnnotatedBeanDefinitionReader {
|
|||
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
|
||||
abd.setScope(scopeMetadata.getScopeName());
|
||||
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
|
||||
if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
|
||||
abd.setPrimary(true);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
|
||||
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
|
||||
abd.setLazyInit(value);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
|
||||
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
||||
abd.setDependsOn(value);
|
||||
}
|
||||
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
|
||||
if (qualifiers != null) {
|
||||
for (Class<? extends Annotation> qualifier : qualifiers) {
|
||||
if (Primary.class.equals(qualifier)) {
|
||||
|
|
@ -137,28 +112,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||
}
|
||||
}
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
|
||||
definitionHolder = applyScopedProxyMode(definitionHolder, scopeMetadata);
|
||||
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
|
||||
|
||||
// Register annotation config processors, if necessary.
|
||||
if (this.includeAnnotationConfig) {
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified scope to the given bean definition.
|
||||
* @param definition the bean definition to configure
|
||||
* @param metadata the corresponding scope metadata
|
||||
* @return the final bean definition to use (potentially a proxy)
|
||||
*/
|
||||
private BeanDefinitionHolder applyScopedProxyMode(BeanDefinitionHolder definition, ScopeMetadata metadata) {
|
||||
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
|
||||
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
|
||||
return definition;
|
||||
}
|
||||
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
|
||||
return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.annotation;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* registering classes one by one ({@link #register}) as well as for classpath scanning
|
||||
* ({@link #scan}).
|
||||
*
|
||||
* <p>Useful for test harnesses or any other scenario where XML-based configuration
|
||||
* is unnecessary or undesired.
|
||||
*
|
||||
* <p>In case of multiple Configuration classes, {@link Bean} methods defined in later
|
||||
* classes will override those defined in earlier classes. This can be leveraged to
|
||||
* deliberately override certain bean definitions via an extra Configuration class.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see AnnotatedBeanDefinitionReader
|
||||
* @see ClassPathBeanDefinitionScanner
|
||||
*/
|
||||
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
|
||||
|
||||
private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this);
|
||||
|
||||
private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AnnotationConfigApplicationContext that needs to be populated
|
||||
* through {@link #add} calls and then manually {@link #refresh refreshed}.
|
||||
*/
|
||||
public AnnotationConfigApplicationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AnnotationConfigApplicationContext, deriving bean
|
||||
* definitions from the given annotated classes and automatically
|
||||
* refreshing the context.
|
||||
* @param annotatedClasses one or more annotated classes,
|
||||
* e.g. {@link Configuration @Configuration} classes
|
||||
*/
|
||||
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
|
||||
register(annotatedClasses);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AnnotationConfigApplicationContext, scanning for bean
|
||||
* definitions in the given packages and automatically refreshing the
|
||||
* context.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
*/
|
||||
public AnnotationConfigApplicationContext(String... basePackages) {
|
||||
scan(basePackages);
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the BeanNameGenerator to use for detected bean classes.
|
||||
* <p>Default is a {@link AnnotationBeanNameGenerator}.
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.reader.setBeanNameGenerator(beanNameGenerator);
|
||||
this.scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ScopeMetadataResolver to use for detected bean classes.
|
||||
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an annotated class to be processed. Allows for programmatically
|
||||
* building a {@link AnnotationConfigApplicationContext}. Note that
|
||||
* {@link AnnotationConfigApplicationContext#refresh()} must be called in
|
||||
* order for the context to fully process the new class.
|
||||
* <p>Calls to {@link #register} are idempotent; adding the same
|
||||
* annotated class more than once has no additional effect.
|
||||
* @param annotatedClasses one or more annotated classes,
|
||||
* e.g. {@link Configuration @Configuration} classes
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void register(Class<?>... annotatedClasses) {
|
||||
this.reader.register(annotatedClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a scan within the specified base packages.
|
||||
* @param basePackages the packages to check for annotated classes
|
||||
*/
|
||||
public void scan(String[] basePackages) {
|
||||
this.scanner.scan(basePackages);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ package org.springframework.context.annotation;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
|
@ -160,4 +161,29 @@ public class AnnotationConfigUtils {
|
|||
return new BeanDefinitionHolder(definition, beanName);
|
||||
}
|
||||
|
||||
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
|
||||
if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
|
||||
abd.setPrimary(true);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
|
||||
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
|
||||
abd.setLazyInit(value);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
|
||||
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
||||
abd.setDependsOn(value);
|
||||
}
|
||||
}
|
||||
|
||||
static BeanDefinitionHolder applyScopedProxyMode(
|
||||
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
|
||||
|
||||
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
|
||||
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
|
||||
return definition;
|
||||
}
|
||||
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
|
||||
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.springframework.util.PatternMatchUtils;
|
|||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see AnnotationConfigApplicationContext#scan
|
||||
* @see org.springframework.stereotype.Component
|
||||
* @see org.springframework.stereotype.Repository
|
||||
* @see org.springframework.stereotype.Service
|
||||
|
|
@ -145,7 +146,7 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
|||
* @see #setScopedProxyMode
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = scopeMetadataResolver;
|
||||
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -206,22 +207,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
|||
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
|
||||
}
|
||||
if (candidate instanceof AnnotatedBeanDefinition) {
|
||||
AnnotatedBeanDefinition abd = (AnnotatedBeanDefinition) candidate;
|
||||
if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
|
||||
abd.setPrimary(true);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
|
||||
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
|
||||
abd.setLazyInit(value);
|
||||
}
|
||||
if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
|
||||
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
||||
abd.setDependsOn(value);
|
||||
}
|
||||
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
|
||||
}
|
||||
if (checkCandidate(beanName, candidate)) {
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
|
||||
definitionHolder = applyScopedProxyMode(definitionHolder, scopeMetadata);
|
||||
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
|
||||
beanDefinitions.add(definitionHolder);
|
||||
registerBeanDefinition(definitionHolder, this.registry);
|
||||
}
|
||||
|
|
@ -300,19 +290,4 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
|||
newDefinition.equals(existingDefinition)); // scanned equivalent class twice
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified scope to the given bean definition.
|
||||
* @param definition the bean definition to configure
|
||||
* @param metadata the corresponding scope metadata
|
||||
* @return the final bean definition to use (potentially a proxy)
|
||||
*/
|
||||
private BeanDefinitionHolder applyScopedProxyMode(BeanDefinitionHolder definition, ScopeMetadata metadata) {
|
||||
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
|
||||
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
|
||||
return definition;
|
||||
}
|
||||
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
|
||||
return ScopedProxyCreator.createScopedProxy(definition, this.registry, proxyTargetClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import org.springframework.stereotype.Component;
|
|||
* @see Lazy
|
||||
* @see Bean
|
||||
* @see ConfigurationClassPostProcessor;
|
||||
* @see ConfigurationClassApplicationContext;
|
||||
* @see AnnotationConfigApplicationContext ;
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
@ -70,7 +70,7 @@ public @interface Configuration {
|
|||
* a bean name will be automatically generated.
|
||||
*
|
||||
* <p>The custom name applies only if the Configuration class is picked up via
|
||||
* component scanning or supplied directly to a {@link ConfigurationClassApplicationContext}.
|
||||
* component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}.
|
||||
* If the Configuration class is registered as a traditional XML bean definition,
|
||||
* the name/id of the bean element will take precedence.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.annotation;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.AbstractRefreshableApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Standalone application context, accepting {@link Configuration @Configuration}
|
||||
* -annotated class literals as input. Useful for test harnesses or any other scenario
|
||||
* where XML-based configuration is unnecessary or undesired.
|
||||
*
|
||||
* <p>In case of multiple Configuration classes, {@link Bean}
|
||||
* methods defined in later classes will override those defined in earlier
|
||||
* classes. This can be leveraged to deliberately override certain bean
|
||||
* definitions via an extra Configuration class.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
* @see Configuration
|
||||
*/
|
||||
public class ConfigurationClassApplicationContext extends AbstractRefreshableApplicationContext {
|
||||
|
||||
private final ConfigurationClassApplicationContext.Delegate delegate =
|
||||
new ConfigurationClassApplicationContext.Delegate();
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClassApplicationContext}, loading bean
|
||||
* definitions from the given {@literal configClasses} and automatically
|
||||
* refreshing the context. <p>Note: if zero classes are specified, the
|
||||
* context will <b>not</b> be refreshed automatically, assuming that
|
||||
* the user will subsequently call {@link #addConfigurationClass(Class)}
|
||||
* and then manually refresh.
|
||||
*
|
||||
* @param configClasses zero or more {@link Configuration} classes
|
||||
* @see #addConfigurationClass(Class)
|
||||
* @see #refresh()
|
||||
*/
|
||||
public ConfigurationClassApplicationContext(Class<?>... configClasses) {
|
||||
if (configClasses.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Class<?> configClass : configClasses) {
|
||||
this.addConfigurationClass(configClass);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link Configuration} class to be processed. Allows for programmatically
|
||||
* building a {@link ConfigurationClassApplicationContext}. Note that
|
||||
* {@link ConfigurationClassApplicationContext#refresh()} must be called in
|
||||
* order for the context to process the new class. Calls to
|
||||
* {@link #addConfigurationClass(Class)} are idempotent; adding the same
|
||||
* Configuration class more than once has no additional effect.
|
||||
* @param configClass new Configuration class to be processed.
|
||||
* @see #ConfigurationClassApplicationContext(Class...)
|
||||
* @see #refresh()
|
||||
*/
|
||||
public void addConfigurationClass(Class<?> configClass) {
|
||||
this.delegate.addConfigurationClass(configClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link BeanDefinition} for each {@link Configuration @Configuration}
|
||||
* class specified. Enables the default set of annotation configuration post
|
||||
* processors, such that {@literal @Autowired}, {@literal @Required}, and associated
|
||||
* annotations can be used within Configuration classes.
|
||||
*
|
||||
* <p>Configuration class bean definitions are registered with generated bean definition
|
||||
* names unless the {@literal value} attribute is provided to the Configuration annotation.
|
||||
*
|
||||
* @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
* @see ConfigurationClassPostProcessor
|
||||
* @see DefaultBeanNameGenerator
|
||||
* @see Configuration#value()
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
|
||||
this.delegate.loadBeanDefinitions(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean instance that matches the given object type.
|
||||
*
|
||||
* @param <T>
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@literal null} is disallowed.
|
||||
* @return bean matching required type
|
||||
* @throws NoSuchBeanDefinitionException if there is not exactly one matching bean
|
||||
* found
|
||||
* @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Class)
|
||||
*/
|
||||
public <T> T getBean(Class<T> requiredType) {
|
||||
return this.delegate.getBean(requiredType, this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates behavior common to {@link ConfigurationClassApplicationContext}
|
||||
* and its {@link org.springframework.web.context.support.ConfigurationClassWebApplicationContext}
|
||||
* variant. Both classes already participate in mutually exclusive superclass
|
||||
* hierarchies, and this class allows for avoiding what would otherwise be a multiple
|
||||
* inheritance problem through composition.
|
||||
*
|
||||
* <p><strong>This class is public by necessity but should be considered private and
|
||||
* subject to change without notice.</strong>
|
||||
*/
|
||||
public static class Delegate {
|
||||
|
||||
private final Set<Class<?>> configClasses = new LinkedHashSet<Class<?>>();
|
||||
|
||||
/**
|
||||
* @see ConfigurationClassApplicationContext#addConfigurationClass(Class)
|
||||
*/
|
||||
public void addConfigurationClass(Class<?> configClass) {
|
||||
Assert.notNull(
|
||||
AnnotationUtils.findAnnotation(configClass, Configuration.class),
|
||||
"Class [" + configClass.getName() + "] is not annotated with @Configuration");
|
||||
this.configClasses.add(configClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ConfigurationClassApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
|
||||
*/
|
||||
public void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
|
||||
// @Autowired and friends must be enabled by default when processing @Configuration classes
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
|
||||
|
||||
for (Class<?> configClass : this.configClasses) {
|
||||
RootBeanDefinition def = new RootBeanDefinition(configClass);
|
||||
String name = AnnotationUtils.findAnnotation(configClass, Configuration.class).value();
|
||||
if (!StringUtils.hasLength(name)) {
|
||||
name = new DefaultBeanNameGenerator().generateBeanName(def, beanFactory);
|
||||
}
|
||||
beanFactory.registerBeanDefinition(name, def);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ConfigurationClassApplicationContext#getBean(Class)
|
||||
*/
|
||||
public <T> T getBean(Class<T> requiredType, ListableBeanFactory context) {
|
||||
Assert.notNull(requiredType, "requiredType may not be null");
|
||||
Assert.notNull(context, "context may not be null");
|
||||
Map<String, T> beansOfType = context.getBeansOfType(requiredType);
|
||||
switch (beansOfType.size()) {
|
||||
case 0:
|
||||
throw new NoSuchBeanDefinitionException(requiredType);
|
||||
case 1:
|
||||
return beansOfType.values().iterator().next();
|
||||
default:
|
||||
throw new NoSuchBeanDefinitionException(requiredType,
|
||||
beansOfType.size() + " matching bean definitions found " +
|
||||
"(" + StringUtils.collectionToCommaDelimitedString(beansOfType.keySet()) + "). " +
|
||||
"Consider qualifying with getBean(Class<T> beanType, String beanName) or " +
|
||||
"declaring one bean definition as @Primary");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|||
* specific bean definition format, are {@link ClassPathXmlApplicationContext}
|
||||
* and {@link FileSystemXmlApplicationContext}, which both derive from the
|
||||
* common {@link AbstractXmlApplicationContext} base class;
|
||||
* {@link org.springframework.context.annotation.ConfigurationClassApplicationContext}
|
||||
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
|
||||
* supports {@literal @Configuration}-annotated classes as a source of bean definitions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -60,7 +60,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|||
* @see AbstractXmlApplicationContext
|
||||
* @see ClassPathXmlApplicationContext
|
||||
* @see FileSystemXmlApplicationContext
|
||||
* @see org.springframework.context.annotation.ConfigurationClassApplicationContext
|
||||
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
*/
|
||||
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
|
||||
|
||||
|
|
@ -223,12 +223,12 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
|||
* Load bean definitions into the given bean factory, typically through
|
||||
* delegating to one or more bean definition readers.
|
||||
* @param beanFactory the bean factory to load bean definitions into
|
||||
* @throws IOException if loading of bean definition files failed
|
||||
* @throws BeansException if parsing of the bean definitions failed
|
||||
* @throws IOException if loading of bean definition files failed
|
||||
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
*/
|
||||
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
|
||||
throws IOException, BeansException;
|
||||
throws BeansException, IOException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public abstract class AbstractXmlApplicationContext extends AbstractRefreshableC
|
|||
* @see #loadBeanDefinitions
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
|
||||
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
|
||||
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,65 +19,36 @@ package org.springframework.context.annotation;
|
|||
import static java.lang.String.format;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class ConfigurationClassApplicationContextTests {
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void emptyConstructorRequiresManualRefresh() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext();
|
||||
context.getBean("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classesMissingConfigurationAnnotationAddedToContextAreDisallowed() {
|
||||
ConfigurationClassApplicationContext ctx =
|
||||
new ConfigurationClassApplicationContext(Config.class);
|
||||
|
||||
// should be fine
|
||||
ctx.addConfigurationClass(ConfigWithCustomName.class);
|
||||
|
||||
// should cause immediate failure (no refresh necessary)
|
||||
try {
|
||||
ctx.addConfigurationClass(ConfigMissingAnnotation.class);
|
||||
fail("expected exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
equalTo("Class [" + ConfigMissingAnnotation.class.getName() + "] " +
|
||||
"is not annotated with @Configuration"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void classesMissingConfigurationAnnotationSuppliedToConstructorAreDisallowed() {
|
||||
new ConfigurationClassApplicationContext(ConfigMissingAnnotation.class);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void nullGetBeanParameterIsDisallowed() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
context.getBean((Class<?>)null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addConfigurationClass() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext();
|
||||
context.addConfigurationClass(Config.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(Config.class, NameConfig.class);
|
||||
context.refresh();
|
||||
context.getBean("testBean");
|
||||
context.addConfigurationClass(NameConfig.class);
|
||||
context.refresh();
|
||||
context.getBean("name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBeanByType() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
TestBean testBean = context.getBean(TestBean.class);
|
||||
assertNotNull("getBean() should not return null", testBean);
|
||||
assertThat(testBean.name, equalTo("foo"));
|
||||
|
|
@ -89,10 +60,10 @@ public class ConfigurationClassApplicationContextTests {
|
|||
*/
|
||||
@Test
|
||||
public void defaultConfigClassBeanNameIsGeneratedProperly() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
|
||||
// attempt to retrieve the instance by its generated bean name
|
||||
Config configObject = (Config) context.getBean(Config.class.getName() + "#0");
|
||||
Config configObject = (Config) context.getBean("configurationClassApplicationContextTests.Config");
|
||||
assertNotNull(configObject);
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +73,8 @@ public class ConfigurationClassApplicationContextTests {
|
|||
*/
|
||||
@Test
|
||||
public void explicitConfigClassBeanNameIsRespected() {
|
||||
ConfigurationClassApplicationContext context =
|
||||
new ConfigurationClassApplicationContext(ConfigWithCustomName.class);
|
||||
AnnotationConfigApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(ConfigWithCustomName.class);
|
||||
|
||||
// attempt to retrieve the instance by its specified name
|
||||
ConfigWithCustomName configObject =
|
||||
|
|
@ -113,7 +84,7 @@ public class ConfigurationClassApplicationContextTests {
|
|||
|
||||
@Test
|
||||
public void getBeanByTypeRaisesNoSuchBeanDefinitionException() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(Config.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
|
||||
|
||||
// attempt to retrieve a bean that does not exist
|
||||
Class<?> targetType = java.util.regex.Pattern.class;
|
||||
|
|
@ -121,7 +92,7 @@ public class ConfigurationClassApplicationContextTests {
|
|||
Object bean = context.getBean(targetType);
|
||||
fail("should have thrown NoSuchBeanDefinitionException, instead got: " + bean);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
assertThat(ex.getMessage(), equalTo(
|
||||
assertThat(ex.getMessage(), containsString(
|
||||
format("No unique bean of type [%s] is defined", targetType.getName())));
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +100,7 @@ public class ConfigurationClassApplicationContextTests {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void getBeanByTypeAmbiguityRaisesException() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(TwoTestBeanConfig.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TwoTestBeanConfig.class);
|
||||
|
||||
try {
|
||||
context.getBean(TestBean.class);
|
||||
|
|
@ -137,10 +108,8 @@ public class ConfigurationClassApplicationContextTests {
|
|||
assertThat(ex.getMessage(),
|
||||
allOf(
|
||||
containsString("No unique bean of type [" + TestBean.class.getName() + "] is defined"),
|
||||
containsString("2 matching bean definitions found"),
|
||||
containsString("tb1"),
|
||||
containsString("tb2"),
|
||||
containsString("Consider qualifying with")
|
||||
containsString("tb2")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -148,7 +117,7 @@ public class ConfigurationClassApplicationContextTests {
|
|||
|
||||
@Test
|
||||
public void autowiringIsEnabledByDefault() {
|
||||
ConfigurationClassApplicationContext context = new ConfigurationClassApplicationContext(AutowiredConfig.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
|
||||
assertThat(context.getBean(TestBean.class).name, equalTo("foo"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
|
|
@ -77,7 +77,7 @@ public class XmlPortletApplicationContext extends AbstractRefreshablePortletAppl
|
|||
* @see #loadBeanDefinitions
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
|
||||
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
|
||||
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.web.context.support;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ScopeMetadataResolver;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.web.context.WebApplicationContext} implementation
|
||||
* which accepts 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
|
||||
* registering classes one by one (specifying class names as config location) as well
|
||||
* as for classpath scanning (specifying base packages as config location).
|
||||
*
|
||||
* <p>This is essentially the equivalent of
|
||||
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
|
||||
* for a web environment.
|
||||
*
|
||||
* <p>To make use of this application context, the "contextClass" context-param for
|
||||
* ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to
|
||||
* the fully-qualified name of this class.
|
||||
*
|
||||
* <p>Unlike {@link XmlWebApplicationContext}, no default configuration class locations
|
||||
* are assumed. Rather, it is a requirement to set the "contextConfigLocation"
|
||||
* context-param for ContextLoader and/or "contextConfigLocation" init-param for
|
||||
* FrameworkServlet.
|
||||
*
|
||||
* <p>Note: In case of multiple {@literal @Configuration} classes, later {@literal @Bean}
|
||||
* definitions will override ones defined in earlier loaded files. This can be leveraged
|
||||
* to deliberately override certain bean definitions via an extra Configuration class.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
*/
|
||||
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {
|
||||
|
||||
/**
|
||||
* Register a {@link BeanDefinition} for each class specified by {@link #getConfigLocations()},
|
||||
* or scan each specified package for annotated classes. Enables the default set of
|
||||
* annotation configuration post processors, such that {@literal @Autowired},
|
||||
* {@literal @Required}, and associated annotations can be used.
|
||||
* <p>Configuration class bean definitions are registered with generated bean definition
|
||||
* names unless the {@literal value} attribute is provided to the stereotype annotation.
|
||||
* @see #getConfigLocations()
|
||||
* @see AnnotatedBeanDefinitionReader
|
||||
* @see ClassPathBeanDefinitionScanner
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
|
||||
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
|
||||
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
|
||||
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
|
||||
if (beanNameGenerator != null) {
|
||||
reader.setBeanNameGenerator(beanNameGenerator);
|
||||
scanner.setBeanNameGenerator(beanNameGenerator);
|
||||
}
|
||||
if (scopeMetadataResolver != null) {
|
||||
reader.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
scanner.setScopeMetadataResolver(scopeMetadataResolver);
|
||||
}
|
||||
|
||||
String[] configLocations = getConfigLocations();
|
||||
if (configLocations != null) {
|
||||
for (String configLocation : configLocations) {
|
||||
try {
|
||||
Class<?> clazz = getClassLoader().loadClass(configLocation);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Successfully resolved class for [" + configLocation + "]");
|
||||
}
|
||||
reader.register(clazz);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not load class for config location [" + configLocation +
|
||||
"] - trying package scan. " + ex);
|
||||
}
|
||||
int count = scanner.scan(configLocation);
|
||||
if (logger.isInfoEnabled()) {
|
||||
if (count == 0) {
|
||||
logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
|
||||
}
|
||||
else {
|
||||
logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
|
||||
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
|
||||
* <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
|
||||
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
|
||||
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
|
||||
*/
|
||||
protected BeanNameGenerator getBeanNameGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader}
|
||||
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
|
||||
* <p>Default is {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}.
|
||||
* @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver
|
||||
* @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
|
||||
*/
|
||||
protected ScopeMetadataResolver getScopeMetadataResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.web.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationClassApplicationContext;
|
||||
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
|
||||
/**
|
||||
* {@link org.springframework.web.context.WebApplicationContext} implementation
|
||||
* which takes its configuration from {@link Configuration @Configuration} classes.
|
||||
* This is essentially the equivalent of
|
||||
* {@link org.springframework.context.annotation.ConfigurationClassApplicationContext}
|
||||
* for a web environment.
|
||||
*
|
||||
* <p>To make use of this application context, the "contextClass" context-param for
|
||||
* ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to
|
||||
* the fully-qualified name of this class.
|
||||
*
|
||||
* <p>Unlike {@link XmlWebApplicationContext}, no default configuration class locations
|
||||
* are assumed. Rather, it is a requirement to set the "contextConfigLocation"
|
||||
* context-param for ContextLoader and/or "contextConfigLocation" init-param for
|
||||
* FrameworkServlet. If these params are not set, an IllegalArgumentException will be thrown.
|
||||
*
|
||||
* <p>Note: In case of multiple {@literal @Configuration} classes, later {@literal @Bean}
|
||||
* definitions will override ones defined in earlier loaded files. This can be leveraged
|
||||
* to deliberately override certain bean definitions via an extra Configuration class.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
* @see ConfigurationClassApplicationContext
|
||||
* @see ConfigurationClassApplicationContext.Delegate
|
||||
*/
|
||||
public class ConfigurationClassWebApplicationContext extends AbstractRefreshableWebApplicationContext {
|
||||
|
||||
private final ConfigurationClassApplicationContext.Delegate delegate =
|
||||
new ConfigurationClassApplicationContext.Delegate();
|
||||
|
||||
/**
|
||||
* Register a {@link BeanDefinition} for each {@link Configuration @Configuration}
|
||||
* class specified by {@link #getConfigLocations()}. Enables the default set of
|
||||
* annotation configuration post processors, such that {@literal @Autowired},
|
||||
* {@literal @Required}, and associated annotations can be used within Configuration
|
||||
* classes.
|
||||
*
|
||||
* <p>Configuration class bean definitions are registered with generated bean
|
||||
* definition names unless the {@literal value} attribute is provided to the
|
||||
* Configuration annotation.
|
||||
*
|
||||
* @throws IllegalArgumentException if configLocations array is null or empty
|
||||
* @throws IOException if any one configLocation is not loadable as a class
|
||||
* @throws IllegalArgumentException if any one loaded class is not annotated with {@literal @Configuration}
|
||||
* @see #getConfigLocations()
|
||||
* @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
* @see ConfigurationClassPostProcessor
|
||||
* @see DefaultBeanNameGenerator
|
||||
* @see Configuration#value()
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
|
||||
throws IOException, BeansException {
|
||||
|
||||
Assert.notEmpty(getConfigLocations(),
|
||||
"No config locations were specified. Is the 'contextConfigLocations' " +
|
||||
"context-param and/or init-param set properly in web.xml?");
|
||||
|
||||
for (String configLocation : getConfigLocations()) {
|
||||
try {
|
||||
Class<?> configClass = ClassUtils.getDefaultClassLoader().loadClass(configLocation);
|
||||
this.delegate.addConfigurationClass(configClass);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new IOException("Could not load @Configuration class [" + configLocation + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.delegate.loadBeanDefinitions(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean instance that matches the given object type.
|
||||
*
|
||||
* @param <T>
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@literal null} is disallowed.
|
||||
* @return bean matching required type
|
||||
* @throws NoSuchBeanDefinitionException if there is not exactly one matching bean
|
||||
* found
|
||||
* @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class)
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Class)
|
||||
*/
|
||||
public <T> T getBean(Class<T> requiredType) {
|
||||
return this.delegate.getBean(requiredType, this);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC
|
|||
* @see #loadBeanDefinitions
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
|
||||
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
|
||||
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
|
||||
|
||||
|
|
@ -111,14 +111,13 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC
|
|||
* therefore this method is just supposed to load and/or register bean definitions.
|
||||
* <p>Delegates to a ResourcePatternResolver for resolving location patterns
|
||||
* into Resource instances.
|
||||
* @throws org.springframework.beans.BeansException in case of bean registration errors
|
||||
* @throws java.io.IOException if the required XML document isn't found
|
||||
* @see #refreshBeanFactory
|
||||
* @see #getConfigLocations
|
||||
* @see #getResources
|
||||
* @see #getResourcePatternResolver
|
||||
*/
|
||||
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
|
||||
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
|
||||
String[] configLocations = getConfigLocations();
|
||||
if (configLocations != null) {
|
||||
for (String configLocation : configLocations) {
|
||||
|
|
|
|||
|
|
@ -16,25 +16,20 @@
|
|||
|
||||
package org.springframework.web.context.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class ConfigurationClassWebApplicationContextTests {
|
||||
|
||||
@Test
|
||||
public void testSingleWellFormedConfigLocation() {
|
||||
ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext();
|
||||
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
|
||||
ctx.setConfigLocation(Config.class.getName());
|
||||
ctx.refresh();
|
||||
|
||||
|
|
@ -42,45 +37,6 @@ public class ConfigurationClassWebApplicationContextTests {
|
|||
assertNotNull(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithoutExplicitlySettingConfigLocations() {
|
||||
ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext();
|
||||
try {
|
||||
ctx.refresh();
|
||||
fail("expected exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString(
|
||||
"Is the 'contextConfigLocations' context-param " +
|
||||
"and/or init-param set properly in web.xml?"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformedConfigLocation() {
|
||||
ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext();
|
||||
ctx.setConfigLocation("garbage");
|
||||
try {
|
||||
ctx.refresh();
|
||||
fail("expected exception");
|
||||
} catch (ApplicationContextException ex) {
|
||||
assertThat(ex.getCause(), is(IOException.class));
|
||||
assertThat(ex.getCause().getMessage(),
|
||||
containsString("Could not load @Configuration class"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonConfigurationClass() {
|
||||
ConfigurationClassWebApplicationContext ctx = new ConfigurationClassWebApplicationContext();
|
||||
ctx.setConfigLocation(NotConfigurationAnnotated.class.getName());
|
||||
try {
|
||||
ctx.refresh();
|
||||
fail("expected exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
containsString("is not annotated with @Configuration"));
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
|
@ -92,7 +48,6 @@ public class ConfigurationClassWebApplicationContextTests {
|
|||
|
||||
static class NotConfigurationAnnotated { }
|
||||
|
||||
static class TestBean {
|
||||
static class TestBean { }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue