View Javadoc
1   /*
2    * Copyright 2002-2014 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 java.util.LinkedHashSet;
20  import java.util.Set;
21  
22  import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
23  import org.springframework.beans.factory.config.BeanDefinition;
24  import org.springframework.beans.factory.config.BeanDefinitionHolder;
25  import org.springframework.beans.factory.support.AbstractBeanDefinition;
26  import org.springframework.beans.factory.support.BeanDefinitionDefaults;
27  import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
28  import org.springframework.beans.factory.support.BeanDefinitionRegistry;
29  import org.springframework.beans.factory.support.BeanNameGenerator;
30  import org.springframework.core.env.Environment;
31  import org.springframework.core.env.EnvironmentCapable;
32  import org.springframework.core.env.StandardEnvironment;
33  import org.springframework.core.io.ResourceLoader;
34  import org.springframework.util.Assert;
35  import org.springframework.util.PatternMatchUtils;
36  
37  /**
38   * A bean definition scanner that detects bean candidates on the classpath,
39   * registering corresponding bean definitions with a given registry ({@code BeanFactory}
40   * or {@code ApplicationContext}).
41   *
42   * <p>Candidate classes are detected through configurable type filters. The
43   * default filters include classes that are annotated with Spring's
44   * {@link org.springframework.stereotype.Component @Component},
45   * {@link org.springframework.stereotype.Repository @Repository},
46   * {@link org.springframework.stereotype.Service @Service}, or
47   * {@link org.springframework.stereotype.Controller @Controller} stereotype.
48   *
49   * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
50   * JSR-330's {@link javax.inject.Named} annotations, if available.
51   *
52   * @author Mark Fisher
53   * @author Juergen Hoeller
54   * @author Chris Beams
55   * @since 2.5
56   * @see AnnotationConfigApplicationContext#scan
57   * @see org.springframework.stereotype.Component
58   * @see org.springframework.stereotype.Repository
59   * @see org.springframework.stereotype.Service
60   * @see org.springframework.stereotype.Controller
61   */
62  public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
63  
64  	private final BeanDefinitionRegistry registry;
65  
66  	private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
67  
68  	private String[] autowireCandidatePatterns;
69  
70  	private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
71  
72  	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
73  
74  	private boolean includeAnnotationConfig = true;
75  
76  
77  	/**
78  	 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory.
79  	 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
80  	 * of a {@code BeanDefinitionRegistry}
81  	 */
82  	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
83  		this(registry, true);
84  	}
85  
86  	/**
87  	 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory.
88  	 * <p>If the passed-in bean factory does not only implement the
89  	 * {@code BeanDefinitionRegistry} interface but also the {@code ResourceLoader}
90  	 * interface, it will be used as default {@code ResourceLoader} as well. This will
91  	 * usually be the case for {@link org.springframework.context.ApplicationContext}
92  	 * implementations.
93  	 * <p>If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader}
94  	 * will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
95  	 * <p>If the the passed-in bean factory also implements {@link EnvironmentCapable} its
96  	 * environment will be used by this reader.  Otherwise, the reader will initialize and
97  	 * use a {@link org.springframework.core.env.StandardEnvironment}. All
98  	 * {@code ApplicationContext} implementations are {@code EnvironmentCapable}, while
99  	 * normal {@code BeanFactory} implementations are not.
100 	 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
101 	 * of a {@code BeanDefinitionRegistry}
102 	 * @param useDefaultFilters whether to include the default filters for the
103 	 * {@link org.springframework.stereotype.Component @Component},
104 	 * {@link org.springframework.stereotype.Repository @Repository},
105 	 * {@link org.springframework.stereotype.Service @Service}, and
106 	 * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
107 	 * @see #setResourceLoader
108 	 * @see #setEnvironment
109 	 */
110 	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
111 		this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
112 	}
113 
114 	/**
115 	 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
116 	 * using the given {@link Environment} when evaluating bean definition profile metadata.
117 	 * <p>If the passed-in bean factory does not only implement the {@code
118 	 * BeanDefinitionRegistry} interface but also the {@link ResourceLoader} interface, it
119 	 * will be used as default {@code ResourceLoader} as well. This will usually be the
120 	 * case for {@link org.springframework.context.ApplicationContext} implementations.
121 	 * <p>If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader}
122 	 * will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
123 	 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
124 	 * of a {@code BeanDefinitionRegistry}
125 	 * @param useDefaultFilters whether to include the default filters for the
126 	 * {@link org.springframework.stereotype.Component @Component},
127 	 * {@link org.springframework.stereotype.Repository @Repository},
128 	 * {@link org.springframework.stereotype.Service @Service}, and
129 	 * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
130 	 * @param environment the Spring {@link Environment} to use when evaluating bean
131 	 * definition profile metadata
132 	 * @since 3.1
133 	 * @see #setResourceLoader
134 	 */
135 	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
136 		super(useDefaultFilters, environment);
137 
138 		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
139 		this.registry = registry;
140 
141 		// Determine ResourceLoader to use.
142 		if (this.registry instanceof ResourceLoader) {
143 			setResourceLoader((ResourceLoader) this.registry);
144 		}
145 	}
146 
147 
148 	/**
149 	 * Return the BeanDefinitionRegistry that this scanner operates on.
150 	 */
151 	public final BeanDefinitionRegistry getRegistry() {
152 		return this.registry;
153 	}
154 
155 	/**
156 	 * Set the defaults to use for detected beans.
157 	 * @see BeanDefinitionDefaults
158 	 */
159 	public void setBeanDefinitionDefaults(BeanDefinitionDefaults beanDefinitionDefaults) {
160 		this.beanDefinitionDefaults =
161 				(beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults());
162 	}
163 
164 	/**
165 	 * Return the defaults to use for detected beans (never {@code null}).
166 	 * @since 4.1
167 	 */
168 	public BeanDefinitionDefaults getBeanDefinitionDefaults() {
169 		return this.beanDefinitionDefaults;
170 	}
171 
172 	/**
173 	 * Set the name-matching patterns for determining autowire candidates.
174 	 * @param autowireCandidatePatterns the patterns to match against
175 	 */
176 	public void setAutowireCandidatePatterns(String... autowireCandidatePatterns) {
177 		this.autowireCandidatePatterns = autowireCandidatePatterns;
178 	}
179 
180 	/**
181 	 * Set the BeanNameGenerator to use for detected bean classes.
182 	 * <p>Default is a {@link AnnotationBeanNameGenerator}.
183 	 */
184 	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
185 		this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
186 	}
187 
188 	/**
189 	 * Set the ScopeMetadataResolver to use for detected bean classes.
190 	 * Note that this will override any custom "scopedProxyMode" setting.
191 	 * <p>The default is an {@link AnnotationScopeMetadataResolver}.
192 	 * @see #setScopedProxyMode
193 	 */
194 	public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
195 		this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
196 	}
197 
198 	/**
199 	 * Specify the proxy behavior for non-singleton scoped beans.
200 	 * Note that this will override any custom "scopeMetadataResolver" setting.
201 	 * <p>The default is {@link ScopedProxyMode#NO}.
202 	 * @see #setScopeMetadataResolver
203 	 */
204 	public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
205 		this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
206 	}
207 
208 	/**
209 	 * Specify whether to register annotation config post-processors.
210 	 * <p>The default is to register the post-processors. Turn this off
211 	 * to be able to ignore the annotations or to process them differently.
212 	 */
213 	public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
214 		this.includeAnnotationConfig = includeAnnotationConfig;
215 	}
216 
217 
218 	/**
219 	 * Perform a scan within the specified base packages.
220 	 * @param basePackages the packages to check for annotated classes
221 	 * @return number of beans registered
222 	 */
223 	public int scan(String... basePackages) {
224 		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
225 
226 		doScan(basePackages);
227 
228 		// Register annotation config processors, if necessary.
229 		if (this.includeAnnotationConfig) {
230 			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
231 		}
232 
233 		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
234 	}
235 
236 	/**
237 	 * Perform a scan within the specified base packages,
238 	 * returning the registered bean definitions.
239 	 * <p>This method does <i>not</i> register an annotation config processor
240 	 * but rather leaves this up to the caller.
241 	 * @param basePackages the packages to check for annotated classes
242 	 * @return set of beans registered if any for tooling registration purposes (never {@code null})
243 	 */
244 	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
245 		Assert.notEmpty(basePackages, "At least one base package must be specified");
246 		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
247 		for (String basePackage : basePackages) {
248 			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
249 			for (BeanDefinition candidate : candidates) {
250 				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
251 				candidate.setScope(scopeMetadata.getScopeName());
252 				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
253 				if (candidate instanceof AbstractBeanDefinition) {
254 					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
255 				}
256 				if (candidate instanceof AnnotatedBeanDefinition) {
257 					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
258 				}
259 				if (checkCandidate(beanName, candidate)) {
260 					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
261 					definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
262 					beanDefinitions.add(definitionHolder);
263 					registerBeanDefinition(definitionHolder, this.registry);
264 				}
265 			}
266 		}
267 		return beanDefinitions;
268 	}
269 
270 	/**
271 	 * Apply further settings to the given bean definition,
272 	 * beyond the contents retrieved from scanning the component class.
273 	 * @param beanDefinition the scanned bean definition
274 	 * @param beanName the generated bean name for the given bean
275 	 */
276 	protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
277 		beanDefinition.applyDefaults(this.beanDefinitionDefaults);
278 		if (this.autowireCandidatePatterns != null) {
279 			beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
280 		}
281 	}
282 
283 	/**
284 	 * Register the specified bean with the given registry.
285 	 * <p>Can be overridden in subclasses, e.g. to adapt the registration
286 	 * process or to register further bean definitions for each scanned bean.
287 	 * @param definitionHolder the bean definition plus bean name for the bean
288 	 * @param registry the BeanDefinitionRegistry to register the bean with
289 	 */
290 	protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
291 		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
292 	}
293 
294 
295 	/**
296 	 * Check the given candidate's bean name, determining whether the corresponding
297 	 * bean definition needs to be registered or conflicts with an existing definition.
298 	 * @param beanName the suggested name for the bean
299 	 * @param beanDefinition the corresponding bean definition
300 	 * @return {@code true} if the bean can be registered as-is;
301 	 * {@code false} if it should be skipped because there is an
302 	 * existing, compatible bean definition for the specified name
303 	 * @throws ConflictingBeanDefinitionException if an existing, incompatible
304 	 * bean definition has been found for the specified name
305 	 */
306 	protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
307 		if (!this.registry.containsBeanDefinition(beanName)) {
308 			return true;
309 		}
310 		BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
311 		BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
312 		if (originatingDef != null) {
313 			existingDef = originatingDef;
314 		}
315 		if (isCompatible(beanDefinition, existingDef)) {
316 			return false;
317 		}
318 		throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
319 				"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
320 				"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
321 	}
322 
323 	/**
324 	 * Determine whether the given new bean definition is compatible with
325 	 * the given existing bean definition.
326 	 * <p>The default implementation considers them as compatible when the existing
327 	 * bean definition comes from the same source or from a non-scanning source.
328 	 * @param newDefinition the new bean definition, originated from scanning
329 	 * @param existingDefinition the existing bean definition, potentially an
330 	 * explicitly defined one or a previously generated one from scanning
331 	 * @return whether the definitions are considered as compatible, with the
332 	 * new definition to be skipped in favor of the existing definition
333 	 */
334 	protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {
335 		return (!(existingDefinition instanceof ScannedGenericBeanDefinition) ||  // explicitly registered overriding bean
336 				newDefinition.getSource().equals(existingDefinition.getSource()) ||  // scanned same file twice
337 				newDefinition.equals(existingDefinition));  // scanned equivalent class twice
338 	}
339 
340 
341 	/**
342 	 * Get the Environment from the given registry if possible, otherwise return a new
343 	 * StandardEnvironment.
344 	 */
345 	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
346 		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
347 		if (registry instanceof EnvironmentCapable) {
348 			return ((EnvironmentCapable) registry).getEnvironment();
349 		}
350 		return new StandardEnvironment();
351 	}
352 
353 }