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}