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}