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(definitionHolder);
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}