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