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

Introduce AnnotationConfigCapableApplicationContext

AnnotationConfigApplicationContext and
AnnotationConfigWebApplicationContext both expose #register and #scan
methods as of the completion of SPR-8320. This change introduces a new
interface that declares each of these methods and refactors ACAC and
ACWAC to implement it.

Beyond information value, this is useful for implementors of the
ApplicationContextInitializer interface, in that users may create an ACI
that works consistently across ACAC and ACWAC for standalone (e.g.
testing, batch) or web (e.g. production) use.

Issue: SPR-8365,SPR-8320
上级 e128ee24
/*
* 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.
......@@ -45,7 +45,8 @@ import org.springframework.util.Assert;
* @see ClassPathBeanDefinitionScanner
* @see org.springframework.context.support.GenericXmlApplicationContext
*/
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
public class AnnotationConfigApplicationContext extends GenericApplicationContext
implements AnnotationConfigCapableApplicationContext {
private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this);
......@@ -101,8 +102,9 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
}
/**
* Set the BeanNameGenerator to use for detected bean classes.
* <p>Default is a {@link AnnotationBeanNameGenerator}.
* {@inheritDoc}
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
......@@ -110,37 +112,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
}
/**
* Set the ScopeMetadataResolver to use for detected bean classes.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
* {@inheritDoc}
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
*/
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) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
/**
* Perform a scan within the specified base packages.
* Note that {@link AnnotationConfigApplicationContext#refresh()} must be
* called in order for the context to fully process the new class.
* @param basePackages the packages to check for annotated classes
* @see #refresh()
*/
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
......
/*
* 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.annotation;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Extension of the {@link ConfigurableApplicationContext} interface to be implemented by
* application contexts that are capable of registering or scanning for annotated classes
* including @{@link Configuration} classes.
*
* <p>This subinterface is not intended for everyday use:
* {@link AnnotationConfigApplicationContext} and its web variant
* {@code AnnotationConfigWebApplicationContext} should be used directly in most cases.
*
* <p>The notable exception to the above is when designing
* {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer} (ACI) implementations: it may be desirable to design an
* ACI such that it may be used interchangeably against a standalone or web-capable
* "AnnotationConfig" application context. For example:
* <pre class="code">
* public class MyACI
* implements ApplicationContextInitializer&lt;AnnotationConfigCapableApplicationContext&gt; {
* void initialize(AnnotationConfigCapableApplicationContext context) {
* context.register(MyConfig1.class, MyConfig2.class);
* context.scan("pkg1", "pkg2");
* // ...
* }
* }</pre>
*
* See {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer} Javadoc for further usage details.
*
* @author Chris Beams
* @since 3.1
* @see AnnotationConfigApplicationContext
* @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext
* @see org.springframework.context.ApplicationContextInitializer
*/
public interface AnnotationConfigCapableApplicationContext extends ConfigurableApplicationContext {
/**
* Set the {@link ScopeMetadataResolver} to use for detected bean classes.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
*/
void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver);
/**
* Set the {@link BeanNameGenerator} to use for detected bean classes.
* <p>The default is an {@link AnnotationBeanNameGenerator}.
*/
void setBeanNameGenerator(BeanNameGenerator beanNameGenerator);
/**
* Register one or more annotated classes to be processed.
* Note that {@link #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 #scan(String...)
* @see #refresh()
*/
void register(Class<?>... annotatedClasses);
/**
* Perform a scan within the specified base packages.
* Note that {@link #refresh()} must be called in order for the context to
* fully process the new class.
* @param basePackages the packages to check for annotated classes
* @see #register(Class...)
* @see #refresh()
*/
void scan(String... basePackages);
}
/*
* Copyright 2002-2009 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.
......@@ -19,34 +19,47 @@ package org.springframework.web.context.support;
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.AnnotationConfigCapableApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ContextLoader;
/**
* {@link org.springframework.web.context.WebApplicationContext} implementation
* which accepts annotated classes as input - in particular
* {@link org.springframework.web.context.WebApplicationContext 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 {@code javax.inject} annotations. Allows for
* registering classes one by one (specifying class names as config location) as well
* classes, but also plain {@link org.springframework.stereotype.Component @Component}
* classes and JSR-330 compliant classes using {@code 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
* <p>To make use of this application context, the
* {@linkplain ContextLoader#CONTEXT_CLASS_PARAM "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
* are assumed. Rather, it is a requirement to set the
* {@linkplain ContextLoader#CONFIG_LOCATION_PARAM "contextConfigLocation"}
* context-param for {@link ContextLoader} and/or "contextConfigLocation" init-param for
* FrameworkServlet. The param-value may contain both fully-qualified
* class names and base packages to scan for components.
* class names and base packages to scan for components. See {@link #loadBeanDefinitions}
* for exact details on how these locations are processed.
*
* <p>As an alternative to setting the "contextConfigLocation" parameter, users may
* implement an {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer} and set the
* {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
* context-param / init-param. In such cases, users should favor the {@link #refresh()}
* and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
* method, which is primarily for use by {@code ContextLoader}
*
* <p>Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}
* definitions will override ones defined in earlier loaded files. This can be leveraged
......@@ -55,14 +68,20 @@ import org.springframework.util.StringUtils;
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.context.annotation.AnnotationConfigCapableApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
*/
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigCapableApplicationContext {
private Class<?>[] annotatedClasses;
private String[] basePackages;
private BeanNameGenerator beanNameGenerator;
private ScopeMetadataResolver scopeMetadataResolver;
/**
* {@inheritDoc}
* <p>This implementation accepts delimited values in the form of fully-qualified
......@@ -109,9 +128,11 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
}
/**
* Set the annotated classes (typically {@code @Configuration} classes)
* for this web application context.
* {@inheritDoc}
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
* @see #register(Class...)
* @see #setConfigLocation(String)
* @see #refresh()
*/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
......@@ -119,8 +140,11 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
}
/**
* Set the base packages to be scanned for annotated classes.
* {@inheritDoc}
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
* @see #register(Class...)
* @see #setConfigLocation(String)
* @see #refresh()
*/
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
......@@ -212,6 +236,10 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
}
}
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = beanNameGenerator;
}
/**
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
......@@ -220,7 +248,11 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
*/
protected BeanNameGenerator getBeanNameGenerator() {
return null;
return this.beanNameGenerator;
}
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.scopeMetadataResolver = scopeMetadataResolver;
}
/**
......@@ -231,7 +263,6 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe
* @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
*/
protected ScopeMetadataResolver getScopeMetadataResolver() {
return null;
return this.scopeMetadataResolver;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册