提交 e128ee24 编写于 作者: C Chris Beams

Introduce AnnotationConfigWAC #scan and #register

Primarily for use in conjunction with ApplicationContextInitializer,
these new #scan and #register methods mirror those in
AnnotationConfigApplicationContext. #setConfigLocation
and #setConfigLocations methods remain for compatibility with
ContextLoader-style initialization, but have been locally overridden
and documented clearly.

AnnotationConfigWebApplicationContext#loadBeanDefinitions Javadoc has
also been updated to explain the processing logic for each of these
potential inputs.

Issue: SPR-8320
上级 56720fc4
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
package org.springframework.web.context.support; 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.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScopeMetadataResolver; import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/** /**
* {@link org.springframework.web.context.WebApplicationContext} implementation * {@link org.springframework.web.context.WebApplicationContext} implementation
...@@ -57,14 +59,92 @@ import org.springframework.context.annotation.ScopeMetadataResolver; ...@@ -57,14 +59,92 @@ import org.springframework.context.annotation.ScopeMetadataResolver;
*/ */
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext { public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {
private Class<?>[] annotatedClasses;
private String[] basePackages;
/**
* {@inheritDoc}
* <p>This implementation accepts delimited values in the form of fully-qualified
* class names, (typically of {@code Configuration} classes) or fully-qualified
* packages to scan for annotated classes. During {@link #loadBeanDefinitions}, these
* locations will be processed in their given order, first attempting to load each
* value as a class. If class loading fails (i.e. a {@code ClassNotFoundException}
* occurs), the value is assumed to be a package and scanning is attempted.
* <p>Note that this method exists primarily for compatibility with Spring's
* {@link org.springframework.web.context.ContextLoader} and that if this application
* context is being configured through an
* {@link org.springframework.context.ApplicationContextInitializer}, use of the
* {@link #register} and {@link #scan} methods are preferred.
* @see #register(Class...)
* @see #scan(String...)
* @see #setConfigLocations(String[])
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
*/
@Override
public void setConfigLocation(String location) {
super.setConfigLocation(location);
}
/**
* {@inheritDoc}
* <p>This implementation accepts individual location values as fully-qualified class
* names (typically {@code @Configuration} classes) or fully-qualified packages to
* scan. During {@link #loadBeanDefinitions}, these locations will be processed in
* order, first attempting to load values as a class, and upon class loading failure
* the value is assumed to be a package to be scanned.
* <p>Note that this method exists primarily for compatibility with Spring's
* {@link org.springframework.web.context.ContextLoader} and that if this application
* context is being configured through an
* {@link org.springframework.context.ApplicationContextInitializer}, use of the
* {@link #register} and {@link #scan} methods are preferred.
* @see #scan(String...)
* @see #register(Class...)
* @see #setConfigLocation(String)
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
*/
@Override
public void setConfigLocations(String[] locations) {
super.setConfigLocations(locations);
}
/**
* Set the annotated classes (typically {@code @Configuration} classes)
* for this web application context.
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
*/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.annotatedClasses = annotatedClasses;
}
/**
* Set the base packages to be scanned for annotated classes.
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
*/
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.basePackages = basePackages;
}
/** /**
* Register a {@link BeanDefinition} for each class specified by {@link #getConfigLocations()}, * Register a {@link org.springframework.beans.factory.config.BeanDefinition} for
* or scan each specified package for annotated classes. Enables the default set of * any classes specified by {@link #register(Class...)} and scan any packages
* annotation configuration post processors, such that {@code @Autowired}, * specified by {@link #scan(String...)}.
* {@code @Required}, and associated annotations can be used. * <p>For any values specified by {@link #setConfigLocation(String)} or
* <p>Configuration class bean definitions are registered with generated bean definition * {@link #setConfigLocations(String[])}, attempt first to load each location as a
* names unless the {@code value} attribute is provided to the stereotype annotation. * class, registering a {@code BeanDefinition} if class loading is successful,
* @see #getConfigLocations() * and if class loading fails (i.e. a {@code ClassNotFoundException} is raised),
* assume the value is a package and attempt to scan it for annotated classes.
* <p>Enables the default set of annotation configuration post processors, such that
* {@code @Autowired}, {@code @Required}, and associated annotations can be used.
* <p>Configuration class bean definitions are registered with generated bean
* definition names unless the {@code value} attribute is provided to the stereotype
* annotation.
* @see #register(Class...)
* @see #scan(String...)
* @see #setConfigLocation()
* @see #setConfigLocations()
* @see AnnotatedBeanDefinitionReader * @see AnnotatedBeanDefinitionReader
* @see ClassPathBeanDefinitionScanner * @see ClassPathBeanDefinitionScanner
*/ */
...@@ -87,6 +167,22 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe ...@@ -87,6 +167,22 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
scanner.setScopeMetadataResolver(scopeMetadataResolver); scanner.setScopeMetadataResolver(scopeMetadataResolver);
} }
if (!ObjectUtils.isEmpty(this.annotatedClasses)) {
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.arrayToCommaDelimitedString(this.annotatedClasses) + "]");
}
reader.register(this.annotatedClasses);
}
if (!ObjectUtils.isEmpty(this.basePackages)) {
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.arrayToCommaDelimitedString(this.basePackages) + "]");
}
scanner.scan(this.basePackages);
}
String[] configLocations = getConfigLocations(); String[] configLocations = getConfigLocations();
if (configLocations != null) { if (configLocations != null) {
for (String configLocation : configLocations) { for (String configLocation : configLocations) {
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
package org.springframework.web.context.support; package org.springframework.web.context.support;
import static org.junit.Assert.*; import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.Test;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -28,8 +28,20 @@ import org.springframework.context.annotation.Configuration; ...@@ -28,8 +28,20 @@ import org.springframework.context.annotation.Configuration;
public class AnnotationConfigWebApplicationContextTests { public class AnnotationConfigWebApplicationContextTests {
@Test @Test
public void testSingleWellFormedConfigLocation() { public void registerSingleClass() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.register(Config.class);
ctx.refresh();
TestBean bean = ctx.getBean(TestBean.class);
assertNotNull(bean);
}
@Test
public void configLocationWithSingleClass() {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.setConfigLocation(Config.class.getName()); ctx.setConfigLocation(Config.class.getName());
ctx.refresh(); ctx.refresh();
...@@ -41,7 +53,7 @@ public class AnnotationConfigWebApplicationContextTests { ...@@ -41,7 +53,7 @@ public class AnnotationConfigWebApplicationContextTests {
@Configuration @Configuration
static class Config { static class Config {
@Bean @Bean
public TestBean testBean() { public TestBean myTestBean() {
return new TestBean(); return new TestBean();
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册