Skip to content

Commit c696e19

Browse files
committed
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
1 parent e128ee2 commit c696e19

File tree

3 files changed

+149
-41
lines changed

3 files changed

+149
-41
lines changed

org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,7 +45,8 @@
4545
* @see ClassPathBeanDefinitionScanner
4646
* @see org.springframework.context.support.GenericXmlApplicationContext
4747
*/
48-
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
48+
public class AnnotationConfigApplicationContext extends GenericApplicationContext
49+
implements AnnotationConfigCapableApplicationContext {
4950

5051
private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this);
5152

@@ -101,46 +102,30 @@ private void delegateEnvironment(ConfigurableEnvironment environment) {
101102
}
102103

103104
/**
104-
* Set the BeanNameGenerator to use for detected bean classes.
105-
* <p>Default is a {@link AnnotationBeanNameGenerator}.
105+
* {@inheritDoc}
106+
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
107+
* and/or {@link #scan(String...)}.
106108
*/
107109
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
108110
this.reader.setBeanNameGenerator(beanNameGenerator);
109111
this.scanner.setBeanNameGenerator(beanNameGenerator);
110112
}
111113

112114
/**
113-
* Set the ScopeMetadataResolver to use for detected bean classes.
114-
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
115+
* {@inheritDoc}
116+
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
117+
* and/or {@link #scan(String...)}.
115118
*/
116119
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
117120
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
118121
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
119122
}
120123

121-
/**
122-
* Register an annotated class to be processed. Allows for programmatically
123-
* building a {@link AnnotationConfigApplicationContext}. Note that
124-
* {@link AnnotationConfigApplicationContext#refresh()} must be called in
125-
* order for the context to fully process the new class.
126-
* <p>Calls to {@link #register} are idempotent; adding the same
127-
* annotated class more than once has no additional effect.
128-
* @param annotatedClasses one or more annotated classes,
129-
* e.g. {@link Configuration @Configuration} classes
130-
* @see #refresh()
131-
*/
132124
public void register(Class<?>... annotatedClasses) {
133125
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
134126
this.reader.register(annotatedClasses);
135127
}
136128

137-
/**
138-
* Perform a scan within the specified base packages.
139-
* Note that {@link AnnotationConfigApplicationContext#refresh()} must be
140-
* called in order for the context to fully process the new class.
141-
* @param basePackages the packages to check for annotated classes
142-
* @see #refresh()
143-
*/
144129
public void scan(String... basePackages) {
145130
Assert.notEmpty(basePackages, "At least one base package must be specified");
146131
this.scanner.scan(basePackages);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation;
18+
19+
import org.springframework.beans.factory.support.BeanNameGenerator;
20+
import org.springframework.context.ConfigurableApplicationContext;
21+
22+
/**
23+
* Extension of the {@link ConfigurableApplicationContext} interface to be implemented by
24+
* application contexts that are capable of registering or scanning for annotated classes
25+
* including @{@link Configuration} classes.
26+
*
27+
* <p>This subinterface is not intended for everyday use:
28+
* {@link AnnotationConfigApplicationContext} and its web variant
29+
* {@code AnnotationConfigWebApplicationContext} should be used directly in most cases.
30+
*
31+
* <p>The notable exception to the above is when designing
32+
* {@link org.springframework.context.ApplicationContextInitializer
33+
* ApplicationContextInitializer} (ACI) implementations: it may be desirable to design an
34+
* ACI such that it may be used interchangeably against a standalone or web-capable
35+
* "AnnotationConfig" application context. For example:
36+
* <pre class="code">
37+
* public class MyACI
38+
* implements ApplicationContextInitializer&lt;AnnotationConfigCapableApplicationContext&gt; {
39+
* void initialize(AnnotationConfigCapableApplicationContext context) {
40+
* context.register(MyConfig1.class, MyConfig2.class);
41+
* context.scan("pkg1", "pkg2");
42+
* // ...
43+
* }
44+
* }</pre>
45+
*
46+
* See {@link org.springframework.context.ApplicationContextInitializer
47+
* ApplicationContextInitializer} Javadoc for further usage details.
48+
*
49+
* @author Chris Beams
50+
* @since 3.1
51+
* @see AnnotationConfigApplicationContext
52+
* @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext
53+
* @see org.springframework.context.ApplicationContextInitializer
54+
*/
55+
public interface AnnotationConfigCapableApplicationContext extends ConfigurableApplicationContext {
56+
57+
/**
58+
* Set the {@link ScopeMetadataResolver} to use for detected bean classes.
59+
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
60+
*/
61+
void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver);
62+
63+
/**
64+
* Set the {@link BeanNameGenerator} to use for detected bean classes.
65+
* <p>The default is an {@link AnnotationBeanNameGenerator}.
66+
*/
67+
void setBeanNameGenerator(BeanNameGenerator beanNameGenerator);
68+
69+
/**
70+
* Register one or more annotated classes to be processed.
71+
* Note that {@link #refresh()} must be called in order for the context to fully
72+
* process the new class.
73+
* <p>Calls to {@link #register} are idempotent; adding the same
74+
* annotated class more than once has no additional effect.
75+
* @param annotatedClasses one or more annotated classes,
76+
* e.g. {@link Configuration @Configuration} classes
77+
* @see #scan(String...)
78+
* @see #refresh()
79+
*/
80+
void register(Class<?>... annotatedClasses);
81+
82+
/**
83+
* Perform a scan within the specified base packages.
84+
* Note that {@link #refresh()} must be called in order for the context to
85+
* fully process the new class.
86+
* @param basePackages the packages to check for annotated classes
87+
* @see #register(Class...)
88+
* @see #refresh()
89+
*/
90+
void scan(String... basePackages);
91+
92+
}

org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,34 +19,47 @@
1919
import org.springframework.beans.factory.support.BeanNameGenerator;
2020
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2121
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
22+
import org.springframework.context.annotation.AnnotationConfigCapableApplicationContext;
2223
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
2324
import org.springframework.context.annotation.ScopeMetadataResolver;
2425
import org.springframework.util.Assert;
2526
import org.springframework.util.ObjectUtils;
2627
import org.springframework.util.StringUtils;
28+
import org.springframework.web.context.ContextLoader;
2729

2830
/**
29-
* {@link org.springframework.web.context.WebApplicationContext} implementation
30-
* which accepts annotated classes as input - in particular
31+
* {@link org.springframework.web.context.WebApplicationContext WebApplicationContext}
32+
* implementation which accepts annotated classes as input - in particular
3133
* {@link org.springframework.context.annotation.Configuration @Configuration}-annotated
32-
* classes, but also plain {@link org.springframework.stereotype.Component @Components}
33-
* and JSR-330 compliant classes using {@code javax.inject} annotations. Allows for
34-
* registering classes one by one (specifying class names as config location) as well
34+
* classes, but also plain {@link org.springframework.stereotype.Component @Component}
35+
* classes and JSR-330 compliant classes using {@code javax.inject} annotations. Allows
36+
* for registering classes one by one (specifying class names as config location) as well
3537
* as for classpath scanning (specifying base packages as config location).
3638
*
3739
* <p>This is essentially the equivalent of
3840
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
3941
* for a web environment.
4042
*
41-
* <p>To make use of this application context, the "contextClass" context-param for
43+
* <p>To make use of this application context, the
44+
* {@linkplain ContextLoader#CONTEXT_CLASS_PARAM "contextClass"} context-param for
4245
* ContextLoader and/or "contextClass" init-param for FrameworkServlet must be set to
4346
* the fully-qualified name of this class.
4447
*
4548
* <p>Unlike {@link XmlWebApplicationContext}, no default configuration class locations
46-
* are assumed. Rather, it is a requirement to set the "contextConfigLocation"
47-
* context-param for ContextLoader and/or "contextConfigLocation" init-param for
49+
* are assumed. Rather, it is a requirement to set the
50+
* {@linkplain ContextLoader#CONFIG_LOCATION_PARAM "contextConfigLocation"}
51+
* context-param for {@link ContextLoader} and/or "contextConfigLocation" init-param for
4852
* FrameworkServlet. The param-value may contain both fully-qualified
49-
* class names and base packages to scan for components.
53+
* class names and base packages to scan for components. See {@link #loadBeanDefinitions}
54+
* for exact details on how these locations are processed.
55+
*
56+
* <p>As an alternative to setting the "contextConfigLocation" parameter, users may
57+
* implement an {@link org.springframework.context.ApplicationContextInitializer
58+
* ApplicationContextInitializer} and set the
59+
* {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
60+
* context-param / init-param. In such cases, users should favor the {@link #refresh()}
61+
* and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
62+
* method, which is primarily for use by {@code ContextLoader}
5063
*
5164
* <p>Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}
5265
* definitions will override ones defined in earlier loaded files. This can be leveraged
@@ -55,14 +68,20 @@
5568
* @author Chris Beams
5669
* @author Juergen Hoeller
5770
* @since 3.0
71+
* @see org.springframework.context.annotation.AnnotationConfigCapableApplicationContext
5872
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
5973
*/
60-
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {
74+
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
75+
implements AnnotationConfigCapableApplicationContext {
6176

6277
private Class<?>[] annotatedClasses;
6378

6479
private String[] basePackages;
6580

81+
private BeanNameGenerator beanNameGenerator;
82+
83+
private ScopeMetadataResolver scopeMetadataResolver;
84+
6685
/**
6786
* {@inheritDoc}
6887
* <p>This implementation accepts delimited values in the form of fully-qualified
@@ -109,18 +128,23 @@ public void setConfigLocations(String[] locations) {
109128
}
110129

111130
/**
112-
* Set the annotated classes (typically {@code @Configuration} classes)
113-
* for this web application context.
131+
* {@inheritDoc}
114132
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
133+
* @see #register(Class...)
134+
* @see #setConfigLocation(String)
135+
* @see #refresh()
115136
*/
116137
public void register(Class<?>... annotatedClasses) {
117138
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
118139
this.annotatedClasses = annotatedClasses;
119140
}
120141

121142
/**
122-
* Set the base packages to be scanned for annotated classes.
143+
* {@inheritDoc}
123144
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
145+
* @see #register(Class...)
146+
* @see #setConfigLocation(String)
147+
* @see #refresh()
124148
*/
125149
public void scan(String... basePackages) {
126150
Assert.notEmpty(basePackages, "At least one base package must be specified");
@@ -212,6 +236,10 @@ protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
212236
}
213237
}
214238

239+
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
240+
this.beanNameGenerator = beanNameGenerator;
241+
}
242+
215243
/**
216244
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
217245
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
@@ -220,7 +248,11 @@ protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
220248
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
221249
*/
222250
protected BeanNameGenerator getBeanNameGenerator() {
223-
return null;
251+
return this.beanNameGenerator;
252+
}
253+
254+
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
255+
this.scopeMetadataResolver = scopeMetadataResolver;
224256
}
225257

226258
/**
@@ -231,7 +263,6 @@ protected BeanNameGenerator getBeanNameGenerator() {
231263
* @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
232264
*/
233265
protected ScopeMetadataResolver getScopeMetadataResolver() {
234-
return null;
266+
return this.scopeMetadataResolver;
235267
}
236-
237268
}

0 commit comments

Comments
 (0)