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.lang.annotation.Annotation;
020import java.util.function.Supplier;
021
022import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
023import org.springframework.beans.factory.config.BeanDefinition;
024import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
025import org.springframework.beans.factory.config.BeanDefinitionHolder;
026import org.springframework.beans.factory.support.AutowireCandidateQualifier;
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.lang.Nullable;
034import org.springframework.util.Assert;
035
036/**
037 * Convenient adapter for programmatic registration of bean classes.
038 *
039 * <p>This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
040 * the same resolution of annotations but for explicitly registered classes only.
041 *
042 * @author Juergen Hoeller
043 * @author Chris Beams
044 * @author Sam Brannen
045 * @author Phillip Webb
046 * @since 3.0
047 * @see AnnotationConfigApplicationContext#register
048 */
049public class AnnotatedBeanDefinitionReader {
050
051        private final BeanDefinitionRegistry registry;
052
053        private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
054
055        private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
056
057        private ConditionEvaluator conditionEvaluator;
058
059
060        /**
061         * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
062         * <p>If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
063         * the {@link Environment} will be inherited, otherwise a new
064         * {@link StandardEnvironment} will be created and used.
065         * @param registry the {@code BeanFactory} to load bean definitions into,
066         * in the form of a {@code BeanDefinitionRegistry}
067         * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
068         * @see #setEnvironment(Environment)
069         */
070        public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
071                this(registry, getOrCreateEnvironment(registry));
072        }
073
074        /**
075         * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
076         * using the given {@link Environment}.
077         * @param registry the {@code BeanFactory} to load bean definitions into,
078         * in the form of a {@code BeanDefinitionRegistry}
079         * @param environment the {@code Environment} to use when evaluating bean definition
080         * profiles.
081         * @since 3.1
082         */
083        public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
084                Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
085                Assert.notNull(environment, "Environment must not be null");
086                this.registry = registry;
087                this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
088                AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
089        }
090
091
092        /**
093         * Get the BeanDefinitionRegistry that this reader operates on.
094         */
095        public final BeanDefinitionRegistry getRegistry() {
096                return this.registry;
097        }
098
099        /**
100         * Set the {@code Environment} to use when evaluating whether
101         * {@link Conditional @Conditional}-annotated component classes should be registered.
102         * <p>The default is a {@link StandardEnvironment}.
103         * @see #registerBean(Class, String, Class...)
104         */
105        public void setEnvironment(Environment environment) {
106                this.conditionEvaluator = new ConditionEvaluator(this.registry, environment, null);
107        }
108
109        /**
110         * Set the {@code BeanNameGenerator} to use for detected bean classes.
111         * <p>The default is a {@link AnnotationBeanNameGenerator}.
112         */
113        public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
114                this.beanNameGenerator =
115                                (beanNameGenerator != null ? beanNameGenerator : AnnotationBeanNameGenerator.INSTANCE);
116        }
117
118        /**
119         * Set the {@code ScopeMetadataResolver} to use for registered component classes.
120         * <p>The default is an {@link AnnotationScopeMetadataResolver}.
121         */
122        public void setScopeMetadataResolver(@Nullable ScopeMetadataResolver scopeMetadataResolver) {
123                this.scopeMetadataResolver =
124                                (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
125        }
126
127
128        /**
129         * Register one or more component classes to be processed.
130         * <p>Calls to {@code register} are idempotent; adding the same
131         * component class more than once has no additional effect.
132         * @param componentClasses one or more component classes,
133         * e.g. {@link Configuration @Configuration} classes
134         */
135        public void register(Class<?>... componentClasses) {
136                for (Class<?> componentClass : componentClasses) {
137                        registerBean(componentClass);
138                }
139        }
140
141        /**
142         * Register a bean from the given bean class, deriving its metadata from
143         * class-declared annotations.
144         * @param beanClass the class of the bean
145         */
146        public void registerBean(Class<?> beanClass) {
147                doRegisterBean(beanClass, null, null, null, null);
148        }
149
150        /**
151         * Register a bean from the given bean class, deriving its metadata from
152         * class-declared annotations.
153         * @param beanClass the class of the bean
154         * @param name an explicit name for the bean
155         * (or {@code null} for generating a default bean name)
156         * @since 5.2
157         */
158        public void registerBean(Class<?> beanClass, @Nullable String name) {
159                doRegisterBean(beanClass, name, null, null, null);
160        }
161
162        /**
163         * Register a bean from the given bean class, deriving its metadata from
164         * class-declared annotations.
165         * @param beanClass the class of the bean
166         * @param qualifiers specific qualifier annotations to consider,
167         * in addition to qualifiers at the bean class level
168         */
169        @SuppressWarnings("unchecked")
170        public void registerBean(Class<?> beanClass, Class<? extends Annotation>... qualifiers) {
171                doRegisterBean(beanClass, null, qualifiers, null, null);
172        }
173
174        /**
175         * Register a bean from the given bean class, deriving its metadata from
176         * class-declared annotations.
177         * @param beanClass the class of the bean
178         * @param name an explicit name for the bean
179         * (or {@code null} for generating a default bean name)
180         * @param qualifiers specific qualifier annotations to consider,
181         * in addition to qualifiers at the bean class level
182         */
183        @SuppressWarnings("unchecked")
184        public void registerBean(Class<?> beanClass, @Nullable String name,
185                        Class<? extends Annotation>... qualifiers) {
186
187                doRegisterBean(beanClass, name, qualifiers, null, null);
188        }
189
190        /**
191         * Register a bean from the given bean class, deriving its metadata from
192         * class-declared annotations, using the given supplier for obtaining a new
193         * instance (possibly declared as a lambda expression or method reference).
194         * @param beanClass the class of the bean
195         * @param supplier a callback for creating an instance of the bean
196         * (may be {@code null})
197         * @since 5.0
198         */
199        public <T> void registerBean(Class<T> beanClass, @Nullable Supplier<T> supplier) {
200                doRegisterBean(beanClass, null, null, supplier, null);
201        }
202
203        /**
204         * Register a bean from the given bean class, deriving its metadata from
205         * class-declared annotations, using the given supplier for obtaining a new
206         * instance (possibly declared as a lambda expression or method reference).
207         * @param beanClass the class of the bean
208         * @param name an explicit name for the bean
209         * (or {@code null} for generating a default bean name)
210         * @param supplier a callback for creating an instance of the bean
211         * (may be {@code null})
212         * @since 5.0
213         */
214        public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier) {
215                doRegisterBean(beanClass, name, null, supplier, null);
216        }
217
218        /**
219         * Register a bean from the given bean class, deriving its metadata from
220         * class-declared annotations.
221         * @param beanClass the class of the bean
222         * @param name an explicit name for the bean
223         * (or {@code null} for generating a default bean name)
224         * @param supplier a callback for creating an instance of the bean
225         * (may be {@code null})
226         * @param customizers one or more callbacks for customizing the factory's
227         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
228         * @since 5.2
229         */
230        public <T> void registerBean(Class<T> beanClass, @Nullable String name, @Nullable Supplier<T> supplier,
231                        BeanDefinitionCustomizer... customizers) {
232
233                doRegisterBean(beanClass, name, null, supplier, customizers);
234        }
235
236        /**
237         * Register a bean from the given bean class, deriving its metadata from
238         * class-declared annotations.
239         * @param beanClass the class of the bean
240         * @param name an explicit name for the bean
241         * @param qualifiers specific qualifier annotations to consider, if any,
242         * in addition to qualifiers at the bean class level
243         * @param supplier a callback for creating an instance of the bean
244         * (may be {@code null})
245         * @param customizers one or more callbacks for customizing the factory's
246         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
247         * @since 5.0
248         */
249        private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
250                        @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
251                        @Nullable BeanDefinitionCustomizer[] customizers) {
252
253                AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
254                if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
255                        return;
256                }
257
258                abd.setInstanceSupplier(supplier);
259                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
260                abd.setScope(scopeMetadata.getScopeName());
261                String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
262
263                AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
264                if (qualifiers != null) {
265                        for (Class<? extends Annotation> qualifier : qualifiers) {
266                                if (Primary.class == qualifier) {
267                                        abd.setPrimary(true);
268                                }
269                                else if (Lazy.class == qualifier) {
270                                        abd.setLazyInit(true);
271                                }
272                                else {
273                                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
274                                }
275                        }
276                }
277                if (customizers != null) {
278                        for (BeanDefinitionCustomizer customizer : customizers) {
279                                customizer.customize(abd);
280                        }
281                }
282
283                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
284                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
285                BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
286        }
287
288
289        /**
290         * Get the Environment from the given registry if possible, otherwise return a new
291         * StandardEnvironment.
292         */
293        private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
294                Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
295                if (registry instanceof EnvironmentCapable) {
296                        return ((EnvironmentCapable) registry).getEnvironment();
297                }
298                return new StandardEnvironment();
299        }
300
301}