Skip to content

Commit 01b8d93

Browse files
committed
AnnotationConfigWebApplicationContext allows for repeated register/scan calls
Restoring consistency with AnnotationConfigApplicationContext. Issue: SPR-10852
1 parent 091712d commit 01b8d93

File tree

2 files changed

+58
-92
lines changed

2 files changed

+58
-92
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void setEnvironment(ConfigurableEnvironment environment) {
120120
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
121121
this.reader.setBeanNameGenerator(beanNameGenerator);
122122
this.scanner.setBeanNameGenerator(beanNameGenerator);
123-
this.getBeanFactory().registerSingleton(
123+
getBeanFactory().registerSingleton(
124124
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
125125
}
126126

@@ -137,9 +137,9 @@ public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver
137137

138138
/**
139139
* Register one or more annotated classes to be processed.
140-
* Note that {@link #refresh()} must be called in order for the context to fully
141-
* process the new class.
142-
* <p>Calls to {@link #register} are idempotent; adding the same
140+
* Note that {@link #refresh()} must be called in order for the context
141+
* to fully process the new class.
142+
* <p>Calls to {@code register} are idempotent; adding the same
143143
* annotated class more than once has no additional effect.
144144
* @param annotatedClasses one or more annotated classes,
145145
* e.g. {@link Configuration @Configuration} classes

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

Lines changed: 54 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 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.
@@ -16,14 +16,17 @@
1616

1717
package org.springframework.web.context.support;
1818

19+
import java.util.Arrays;
20+
import java.util.LinkedHashSet;
21+
import java.util.Set;
22+
1923
import org.springframework.beans.factory.support.BeanNameGenerator;
2024
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2125
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
2226
import org.springframework.context.annotation.AnnotationConfigUtils;
2327
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
2428
import org.springframework.context.annotation.ScopeMetadataResolver;
2529
import org.springframework.util.Assert;
26-
import org.springframework.util.ObjectUtils;
2730
import org.springframework.util.StringUtils;
2831
import org.springframework.web.context.ContextLoader;
2932

@@ -64,7 +67,7 @@
6467
* {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
6568
* context-param / init-param. In such cases, users should favor the {@link #refresh()}
6669
* and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
67-
* method, which is primarily for use by {@code ContextLoader}
70+
* method, which is primarily for use by {@code ContextLoader}.
6871
*
6972
* <p>Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}
7073
* definitions will override ones defined in earlier loaded files. This can be leveraged
@@ -77,64 +80,59 @@
7780
*/
7881
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext {
7982

80-
private Class<?>[] annotatedClasses;
81-
82-
private String[] basePackages;
83-
8483
private BeanNameGenerator beanNameGenerator;
8584

8685
private ScopeMetadataResolver scopeMetadataResolver;
8786

87+
private final Set<Class<?>> annotatedClasses = new LinkedHashSet<Class<?>>();
88+
89+
private final Set<String> basePackages = new LinkedHashSet<String>();
90+
91+
8892
/**
89-
* {@inheritDoc}
90-
* <p>This implementation accepts delimited values in the form of fully-qualified
91-
* class names, (typically of {@code Configuration} classes) or fully-qualified
92-
* packages to scan for annotated classes. During {@link #loadBeanDefinitions}, these
93-
* locations will be processed in their given order, first attempting to load each
94-
* value as a class. If class loading fails (i.e. a {@code ClassNotFoundException}
95-
* occurs), the value is assumed to be a package and scanning is attempted.
96-
* <p>Note that this method exists primarily for compatibility with Spring's
97-
* {@link org.springframework.web.context.ContextLoader} and that if this application
98-
* context is being configured through an
99-
* {@link org.springframework.context.ApplicationContextInitializer}, use of the
100-
* {@link #register} and {@link #scan} methods are preferred.
101-
* @see #register(Class...)
102-
* @see #scan(String...)
103-
* @see #setConfigLocations(String[])
104-
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
93+
* Set a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
94+
* and/or {@link ClassPathBeanDefinitionScanner}.
95+
* <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
96+
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
97+
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
10598
*/
106-
@Override
107-
public void setConfigLocation(String location) {
108-
super.setConfigLocation(location);
99+
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
100+
this.beanNameGenerator = beanNameGenerator;
109101
}
110102

111103
/**
112-
* {@inheritDoc}
113-
* <p>This implementation accepts individual location values as fully-qualified class
114-
* names (typically {@code @Configuration} classes) or fully-qualified packages to
115-
* scan. During {@link #loadBeanDefinitions}, these locations will be processed in
116-
* order, first attempting to load values as a class, and upon class loading failure
117-
* the value is assumed to be a package to be scanned.
118-
* <p>Note that this method exists primarily for compatibility with Spring's
119-
* {@link org.springframework.web.context.ContextLoader} and that if this application
120-
* context is being configured through an
121-
* {@link org.springframework.context.ApplicationContextInitializer}, use of the
122-
* {@link #register} and {@link #scan} methods are preferred.
123-
* @see #scan(String...)
124-
* @see #register(Class...)
125-
* @see #setConfigLocation(String)
126-
* @see #loadBeanDefinitions(DefaultListableBeanFactory)
104+
* Return the custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
105+
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
127106
*/
128-
@Override
129-
public void setConfigLocations(String[] locations) {
130-
super.setConfigLocations(locations);
107+
protected BeanNameGenerator getBeanNameGenerator() {
108+
return this.beanNameGenerator;
131109
}
132110

111+
/**
112+
* Set a custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader}
113+
* and/or {@link ClassPathBeanDefinitionScanner}.
114+
* <p>Default is an {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}.
115+
* @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver
116+
* @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
117+
*/
118+
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
119+
this.scopeMetadataResolver = scopeMetadataResolver;
120+
}
121+
122+
/**
123+
* Return the custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader}
124+
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
125+
*/
126+
protected ScopeMetadataResolver getScopeMetadataResolver() {
127+
return this.scopeMetadataResolver;
128+
}
129+
130+
133131
/**
134132
* Register one or more annotated classes to be processed.
135-
* Note that {@link #refresh()} must be called in order for the context to fully
136-
* process the new class.
137-
* <p>Calls to {@link #register} are idempotent; adding the same
133+
* Note that {@link #refresh()} must be called in order for the context
134+
* to fully process the new class.
135+
* <p>Calls to {@code register} are idempotent; adding the same
138136
* annotated class more than once has no additional effect.
139137
* @param annotatedClasses one or more annotated classes,
140138
* e.g. {@link org.springframework.context.annotation.Configuration @Configuration} classes
@@ -145,7 +143,7 @@ public void setConfigLocations(String[] locations) {
145143
*/
146144
public void register(Class<?>... annotatedClasses) {
147145
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
148-
this.annotatedClasses = annotatedClasses;
146+
this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));
149147
}
150148

151149
/**
@@ -160,9 +158,10 @@ public void register(Class<?>... annotatedClasses) {
160158
*/
161159
public void scan(String... basePackages) {
162160
Assert.notEmpty(basePackages, "At least one base package must be specified");
163-
this.basePackages = basePackages;
161+
this.basePackages.addAll(Arrays.asList(basePackages));
164162
}
165163

164+
166165
/**
167166
* Register a {@link org.springframework.beans.factory.config.BeanDefinition} for
168167
* any classes specified by {@link #register(Class...)} and scan any packages
@@ -205,20 +204,20 @@ protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
205204
scanner.setScopeMetadataResolver(scopeMetadataResolver);
206205
}
207206

208-
if (!ObjectUtils.isEmpty(this.annotatedClasses)) {
207+
if (!this.annotatedClasses.isEmpty()) {
209208
if (logger.isInfoEnabled()) {
210209
logger.info("Registering annotated classes: [" +
211-
StringUtils.arrayToCommaDelimitedString(this.annotatedClasses) + "]");
210+
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
212211
}
213-
reader.register(this.annotatedClasses);
212+
reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
214213
}
215214

216-
if (!ObjectUtils.isEmpty(this.basePackages)) {
215+
if (!this.basePackages.isEmpty()) {
217216
if (logger.isInfoEnabled()) {
218217
logger.info("Scanning base packages: [" +
219-
StringUtils.arrayToCommaDelimitedString(this.basePackages) + "]");
218+
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
220219
}
221-
scanner.scan(this.basePackages);
220+
scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
222221
}
223222

224223
String[] configLocations = getConfigLocations();
@@ -250,37 +249,4 @@ protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
250249
}
251250
}
252251

253-
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
254-
this.beanNameGenerator = beanNameGenerator;
255-
}
256-
257-
/**
258-
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
259-
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
260-
* <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
261-
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
262-
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
263-
*/
264-
protected BeanNameGenerator getBeanNameGenerator() {
265-
return this.beanNameGenerator;
266-
}
267-
268-
/**
269-
* Set the {@link ScopeMetadataResolver} to use for detected bean classes.
270-
* <p>The default is an {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}.
271-
*/
272-
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
273-
this.scopeMetadataResolver = scopeMetadataResolver;
274-
}
275-
276-
/**
277-
* Provide a custom {@link ScopeMetadataResolver} for use with {@link AnnotatedBeanDefinitionReader}
278-
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
279-
* <p>Default is {@link org.springframework.context.annotation.AnnotationScopeMetadataResolver}.
280-
* @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver
281-
* @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver
282-
*/
283-
protected ScopeMetadataResolver getScopeMetadataResolver() {
284-
return this.scopeMetadataResolver;
285-
}
286252
}

0 commit comments

Comments
 (0)