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}