001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.context.annotation; 018 019import java.util.LinkedHashSet; 020import java.util.Set; 021 022import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; 023import org.springframework.beans.factory.config.BeanDefinition; 024import org.springframework.beans.factory.config.BeanDefinitionHolder; 025import org.springframework.beans.factory.support.AbstractBeanDefinition; 026import org.springframework.beans.factory.support.BeanDefinitionDefaults; 027import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; 028import org.springframework.beans.factory.support.BeanDefinitionRegistry; 029import org.springframework.beans.factory.support.BeanNameGenerator; 030import org.springframework.core.env.Environment; 031import org.springframework.core.env.EnvironmentCapable; 032import org.springframework.core.env.StandardEnvironment; 033import org.springframework.core.io.ResourceLoader; 034import org.springframework.util.Assert; 035import org.springframework.util.PatternMatchUtils; 036 037/** 038 * A bean definition scanner that detects bean candidates on the classpath, 039 * registering corresponding bean definitions with a given registry ({@code BeanFactory} 040 * or {@code ApplicationContext}). 041 * 042 * <p>Candidate classes are detected through configurable type filters. The 043 * default filters include classes that are annotated with Spring's 044 * {@link org.springframework.stereotype.Component @Component}, 045 * {@link org.springframework.stereotype.Repository @Repository}, 046 * {@link org.springframework.stereotype.Service @Service}, or 047 * {@link org.springframework.stereotype.Controller @Controller} stereotype. 048 * 049 * <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and 050 * JSR-330's {@link javax.inject.Named} annotations, if available. 051 * 052 * @author Mark Fisher 053 * @author Juergen Hoeller 054 * @author Chris Beams 055 * @since 2.5 056 * @see AnnotationConfigApplicationContext#scan 057 * @see org.springframework.stereotype.Component 058 * @see org.springframework.stereotype.Repository 059 * @see org.springframework.stereotype.Service 060 * @see org.springframework.stereotype.Controller 061 */ 062public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider { 063 064 private final BeanDefinitionRegistry registry; 065 066 private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults(); 067 068 private String[] autowireCandidatePatterns; 069 070 private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); 071 072 private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); 073 074 private boolean includeAnnotationConfig = true; 075 076 077 /** 078 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory. 079 * @param registry the {@code BeanFactory} to load bean definitions into, in the form 080 * of a {@code BeanDefinitionRegistry} 081 */ 082 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) { 083 this(registry, true); 084 } 085 086 /** 087 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory. 088 * <p>If the passed-in bean factory does not only implement the 089 * {@code BeanDefinitionRegistry} interface but also the {@code ResourceLoader} 090 * interface, it will be used as default {@code ResourceLoader} as well. This will 091 * usually be the case for {@link org.springframework.context.ApplicationContext} 092 * implementations. 093 * <p>If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader} 094 * will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. 095 * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its 096 * environment will be used by this reader. Otherwise, the reader will initialize and 097 * use a {@link org.springframework.core.env.StandardEnvironment}. All 098 * {@code ApplicationContext} implementations are {@code EnvironmentCapable}, while 099 * 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, 136 Environment environment) { 137 138 this(registry, useDefaultFilters, environment, 139 (registry instanceof ResourceLoader ? (ResourceLoader) registry : null)); 140 } 141 142 /** 143 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and 144 * using the given {@link Environment} when evaluating bean definition profile metadata. 145 * @param registry the {@code BeanFactory} to load bean definitions into, in the form 146 * of a {@code BeanDefinitionRegistry} 147 * @param useDefaultFilters whether to include the default filters for the 148 * {@link org.springframework.stereotype.Component @Component}, 149 * {@link org.springframework.stereotype.Repository @Repository}, 150 * {@link org.springframework.stereotype.Service @Service}, and 151 * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations 152 * @param environment the Spring {@link Environment} to use when evaluating bean 153 * definition profile metadata 154 * @param resourceLoader the {@link ResourceLoader} to use 155 * @since 4.3.6 156 */ 157 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, 158 Environment environment, ResourceLoader resourceLoader) { 159 160 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 161 this.registry = registry; 162 163 if (useDefaultFilters) { 164 registerDefaultFilters(); 165 } 166 setEnvironment(environment); 167 setResourceLoader(resourceLoader); 168 } 169 170 171 /** 172 * Return the BeanDefinitionRegistry that this scanner operates on. 173 */ 174 public final BeanDefinitionRegistry getRegistry() { 175 return this.registry; 176 } 177 178 /** 179 * Set the defaults to use for detected beans. 180 * @see BeanDefinitionDefaults 181 */ 182 public void setBeanDefinitionDefaults(BeanDefinitionDefaults beanDefinitionDefaults) { 183 this.beanDefinitionDefaults = 184 (beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults()); 185 } 186 187 /** 188 * Return the defaults to use for detected beans (never {@code null}). 189 * @since 4.1 190 */ 191 public BeanDefinitionDefaults getBeanDefinitionDefaults() { 192 return this.beanDefinitionDefaults; 193 } 194 195 /** 196 * Set the name-matching patterns for determining autowire candidates. 197 * @param autowireCandidatePatterns the patterns to match against 198 */ 199 public void setAutowireCandidatePatterns(String... autowireCandidatePatterns) { 200 this.autowireCandidatePatterns = autowireCandidatePatterns; 201 } 202 203 /** 204 * Set the BeanNameGenerator to use for detected bean classes. 205 * <p>Default is a {@link AnnotationBeanNameGenerator}. 206 */ 207 public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { 208 this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator()); 209 } 210 211 /** 212 * Set the ScopeMetadataResolver to use for detected bean classes. 213 * Note that this will override any custom "scopedProxyMode" setting. 214 * <p>The default is an {@link AnnotationScopeMetadataResolver}. 215 * @see #setScopedProxyMode 216 */ 217 public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { 218 this.scopeMetadataResolver = 219 (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver()); 220 } 221 222 /** 223 * Specify the proxy behavior for non-singleton scoped beans. 224 * Note that this will override any custom "scopeMetadataResolver" setting. 225 * <p>The default is {@link ScopedProxyMode#NO}. 226 * @see #setScopeMetadataResolver 227 */ 228 public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) { 229 this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode); 230 } 231 232 /** 233 * Specify whether to register annotation config post-processors. 234 * <p>The default is to register the post-processors. Turn this off 235 * to be able to ignore the annotations or to process them differently. 236 */ 237 public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) { 238 this.includeAnnotationConfig = includeAnnotationConfig; 239 } 240 241 242 /** 243 * Perform a scan within the specified base packages. 244 * @param basePackages the packages to check for annotated classes 245 * @return number of beans registered 246 */ 247 public int scan(String... basePackages) { 248 int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); 249 250 doScan(basePackages); 251 252 // Register annotation config processors, if necessary. 253 if (this.includeAnnotationConfig) { 254 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 255 } 256 257 return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart); 258 } 259 260 /** 261 * Perform a scan within the specified base packages, 262 * returning the registered bean definitions. 263 * <p>This method does <i>not</i> register an annotation config processor 264 * but rather leaves this up to the caller. 265 * @param basePackages the packages to check for annotated classes 266 * @return set of beans registered if any for tooling registration purposes (never {@code null}) 267 */ 268 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { 269 Assert.notEmpty(basePackages, "At least one base package must be specified"); 270 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); 271 for (String basePackage : basePackages) { 272 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 273 for (BeanDefinition candidate : candidates) { 274 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); 275 candidate.setScope(scopeMetadata.getScopeName()); 276 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); 277 if (candidate instanceof AbstractBeanDefinition) { 278 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); 279 } 280 if (candidate instanceof AnnotatedBeanDefinition) { 281 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); 282 } 283 if (checkCandidate(beanName, candidate)) { 284 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); 285 definitionHolder = 286 AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 287 beanDefinitions.add(definit="sourceLineNo">288 registerBeanDefinition(definitionHolder, this.registry); 289 } 290 } 291 } 292 return beanDefinitions; 293 } 294 295 /** 296 * Apply further settings to the given bean definition, 297 * beyond the contents retrieved from scanning the component class. 298 * @param beanDefinition the scanned bean definition 299 * @param beanName the generated bean name for the given bean 300 */ 301 protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) { 302 beanDefinition.applyDefaults(this.beanDefinitionDefaults); 303 if (this.autowireCandidatePatterns != null) { 304 beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName)); 305 } 306 } 307 308 /** 309 * Register the specified bean with the given registry. 310 * <p>Can be overridden in subclasses, e.g. to adapt the registration 311 * process or to register further bean definitions for each scanned bean. 312 * @param definitionHolder the bean definition plus bean name for the bean 313 * @param registry the BeanDefinitionRegistry to register the bean with 314 */ 315 protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { 316 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); 317 } 318 319 320 /** 321 * Check the given candidate's bean name, determining whether the corresponding 322 * bean definition needs to be registered or conflicts with an existing definition. 323 * @param beanName the suggested name for the bean 324 * @param beanDefinition the corresponding bean definition 325 * @return {@code true} if the bean can be registered as-is; 326 * {@code false} if it should be skipped because there is an 327 * existing, compatible bean definition for the specified name 328 * @throws ConflictingBeanDefinitionException if an existing, incompatible 329 * bean definition has been found for the specified name 330 */ 331 protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException { 332 if (!this.registry.containsBeanDefinition(beanName)) { 333 return true; 334 } 335 BeanDefinition existingDef = this.registry.getBeanDefinition(beanName); 336 BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition(); 337 if (originatingDef != null) { 338 existingDef = originatingDef; 339 } 340 if (isCompatible(beanDefinition, existingDef)) { 341 return false; 342 } 343 throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName + 344 "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " + 345 "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]"); 346 } 347 348 /** 349 * Determine whether the given new bean definition is compatible with 350 * the given existing bean definition. 351 * <p>The default implementation considers them as compatible when the existing 352 * bean definition comes from the same source or from a non-scanning source. 353 * @param newDefinition the new bean definition, originated from scanning 354 * @param existingDefinition the existing bean definition, potentially an 355 * explicitly defined one or a previously generated one from scanning 356 * @return whether the definitions are considered as compatible, with the 357 * new definition to be skipped in favor of the existing definition 358 */ 359 protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) { 360 return (!(existingDefinition instanceof ScannedGenericBeanDefinition) || // explicitly registered overriding bean 361 newDefinition.getSource().equals(existingDefinition.getSource()) || // scanned same file twice 362 newDefinition.equals(existingDefinition)); // scanned equivalent class twice 363 } 364 365 366 /** 367 * Get the Environment from the given registry if possible, otherwise return a new 368 * StandardEnvironment. 369 */ 370 private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) { 371 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 372 if (registry instanceof EnvironmentCapable) { 373 return ((EnvironmentCapable) registry).getEnvironment(); 374 } 375 return new StandardEnvironment(); 376 } 377 378}