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.lang.annotation.Annotation;
020
021import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
022import org.springframework.beans.factory.config.BeanDefinitionHolder;
023import org.springframework.beans.factory.support.AutowireCandidateQualifier;
024import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
025import org.springframework.beans.factory.support.BeanDefinitionRegistry;
026import org.springframework.beans.factory.support.BeanNameGenerator;
027import org.springframework.core.env.Environment;
028import org.springframework.core.env.EnvironmentCapable;
029import org.springframework.core.env.StandardEnvironment;
030import org.springframework.util.Assert;
031
032/**
033 * Convenient adapter for programmatic registration of annotated bean classes.
034 * This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
035 * the same resolution of annotations but for explicitly registered classes only.
036 *
037 * @author Juergen Hoeller
038 * @author Chris Beams
039 * @author Sam Brannen
040 * @author Phillip Webb
041 * @since 3.0
042 * @see AnnotationConfigApplicationContext#register
043 */
044public class AnnotatedBeanDefinitionReader {
045
046        private final BeanDefinitionRegistry registry;
047
048        private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
049
050        private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
051
052        private ConditionEvaluator conditionEvaluator;
053
054
055        /**
056         * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
057         * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
058         * the {@link Environment} will be inherited, otherwise a new
059         * {@link StandardEnvironment} will be created and used.
060         * @param registry the {@code BeanFactory} to load bean definitions into,
061         * in the form of a {@code BeanDefinitionRegistry}
062         * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
063         * @see #setEnvironment(Environment)
064         */
065        public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
066                this(registry, getOrCreateEnvironment(registry));
067        }
068
069        /**
070         * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using
071         * the given {@link Environment}.
072         * @param registry the {@code BeanFactory} to load bean definitions into,
073         * in the form of a {@code BeanDefinitionRegistry}
074         * @param environment the {@code Environment} to use when evaluating bean definition
075         * profiles.
076         * @since 3.1
077         */
078        public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
079                Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
080                Assert.notNull(environment, "Environment must not be null");
081                this.registry = registry;
082                this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
083                AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
084        }
085
086
087        /**
088         * Return the BeanDefinitionRegistry that this scanner operates on.
089         */
090        public final BeanDefinitionRegistry getRegistry() {
091                return this.registry;
092        }
093
094        /**
095         * Set the Environment to use when evaluating whether
096         * {@link Conditional @Conditional}-annotated component classes should be registered.
097         * <p>The default is a {@link StandardEnvironment}.
098         * @see #registerBean(Class, String, Class...)
099         */
100        public void setEnvironment(Environment environment) {
101                this.conditionEvaluator = new ConditionEvaluator(this.registry, environment, null);
102        }
103
104        /**
105         * Set the BeanNameGenerator to use for detected bean classes.
106         * <p>The default is a {@link AnnotationBeanNameGenerator}.
107         */
108        public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
109                this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
110        }
111
112        /**
113         * Set the ScopeMetadataResolver to use for detected bean classes.
114         * <p>The default is an {@link AnnotationScopeMetadataResolver}.
115         */
116        public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
117                this.scopeMetadataResolver =
118                                (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
119        }
120
121
122        /**
123         * Register one or more annotated classes to be processed.
124         * <p>Calls to {@code register} are idempotent; adding the same
125         * annotated class more than once has no additional effect.
126         * @param annotatedClasses one or more annotated classes,
127         * e.g. {@link Configuration @Configuration} classes
128         */
129        public void register(Class<?>... annotatedClasses) {
130                for (Class<?> annotatedClass : annotatedClasses) {
131                        registerBean(annotatedClass);
132                }
133        }
134
135        /**
136         * Register a bean from the given bean class, deriving its metadata from
137         * class-declared annotations.
138         * @param annotatedClass the class of the bean
139         */
140        @SuppressWarnings("unchecked")
141        public void registerBean(Class<?> annotatedClass) {
142                registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
143        }
144
145        /**
146         * Register a bean from the given bean class, deriving its metadata from
147         * class-declared annotations.
148         * @param annotatedClass the class of the bean
149         * @param qualifiers specific qualifier annotations to consider,
150         * in addition to qualifiers at the bean class level
151         */
152        @SuppressWarnings("unchecked")
153        public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
154                registerBean(annotatedClass, null, qualifiers);
155        }
156
157        /**
158         * Register a bean from the given bean class, deriving its metadata from
159         * class-declared annotations.
160         * @param annotatedClass the class of the bean
161         * @param name an explicit name for the bean
162         * @param qualifiers specific qualifier annotations to consider,
163         * in addition to qualifiers at the bean class level
164         */
165        @SuppressWarnings("unchecked")
166        public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
167                AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
168                if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
169                        return;
170                }
171
172                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
173                abd.setScope(scopeMetadata.getScopeName());
174                String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
175                AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
176                if (qualifiers != null) {
177                        for (Class<? extends Annotation> qualifier : qualifiers) {
178                                if (Primary.class == qualifier) {
179                                        abd.setPrimary(true);
180                                }
181                                else if (Lazy.class == qualifier) {
182                                        abd.setLazyInit(true);
183                                }
184                                else {
185                                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
186                                }
187                        }
188                }
189
190                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
191                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
192                BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
193        }
194
195
196        /**
197         * Get the Environment from the given registry if possible, otherwise return a new
198         * StandardEnvironment.
199         */
200        private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
201                Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
202                if (registry instanceof EnvironmentCapable) {
203                        return ((EnvironmentCapable) registry).getEnvironment();
204                }
205                return new StandardEnvironment();
206        }
207
208}