读取一组已经被完整解析的配置类ConfigurationClass
,向给定bean
容器BeanDefinitionRegistry
注册其中所有的bean
定义。
该内部工具由Spring
BeanDefinitionRegistryPostProcessor
ConfigurationClassParser
使用。在容器启动过程中, ConfigurationClassParser
会在BeanDefinitionRegistryPostProcessor
应用阶段被调用,用于发现应用中所有的配置类ConfigurationClass
,然后交给ConfigurationClassBeanDefinitionReader
将这些配置类中的bean
定义注册到容器。
SpringApplication.run()
=>refreshContext(ConfigurableApplicationContext context)
=> EmbeddedWebApplicationContext.refresh()
=> AbstractApplicationContext.refresh()
=>invokeBeanFactoryPostProcessors()
=> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
=> ConfigurationClassPostProcessor.processConfigBeanDefinitions()
=> ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()
// 这是该类对外提供的唯一的服务方法入口
// configurationModel 通常来自 ConfigurationClassParser
void loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
/**
* Reads a given fully-populated set of ConfigurationClass instances, registering bean
* definitions with the given BeanDefinitionRegistry based on its contents.
*
* 读取一组带有完整解析数据的ConfigurationClass集合,基于他们所携带的信息向给定BeanDefinitionRegistry
* 注册其中所有的bean定义。
*
* This class was modeled after the BeanDefinitionReader hierarchy, but does
* not implement/extend any of its artifacts as a set of configuration classes is not a
* Resource.
*
* @author Chris Beams
* @author Juergen Hoeller
* @author Phillip Webb
* @author Sam Brannen
* @since 3.0
* @see ConfigurationClassParser
*/
class ConfigurationClassBeanDefinitionReader {
private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class);
private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private final BeanDefinitionRegistry registry;
private final SourceExtractor sourceExtractor;
private final ResourceLoader resourceLoader;
private final Environment environment;
private final BeanNameGenerator importBeanNameGenerator;
private final ImportRegistry importRegistry;
//对@Conditional注解求值的工具类
private final ConditionEvaluator conditionEvaluator;
/**
* Create a new ConfigurationClassBeanDefinitionReader instance that will be used
* to populate the given BeanDefinitionRegistry.
*
* 创建一个新的往指定的BeanDefinitionRegistry填充bean定义的
* ConfigurationClassBeanDefinitionReader 实例
*/
ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator,
ImportRegistry importRegistry) {
this.registry = registry;
this.sourceExtractor = sourceExtractor;
this.resourceLoader = resourceLoader;
this.environment = environment;
this.importBeanNameGenerator = importBeanNameGenerator;
this.importRegistry = importRegistry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
/**
* Read configurationModel, registering bean definitions
* with the registry based on its contents.
* configurationModel 是一组ConfigurationClass,表示一组配置类,该方法从中读取bean定义
* 并注册到bean容器
*/
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
//遍历处理参数configurationModel中的每个配置类
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
/**
* Read a particular ConfigurationClass, registering bean definitions
* for the class itself and all of its Bean methods.
* 从指定的一个配置类ConfigurationClass中提取bean定义信息并注册bean定义到bean容器 :
* 1. 配置类本身要注册为bean定义
* 2. 配置类中的@Bean注解方法要注册为配置类
*/
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
// 如果这是一个通过import机制被导入进来的配置类,将它本身作为一个bean定义注册到容器
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 现在把配置类里面@Bean注解的方法作为bean定义注册到容器
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 从配置类导入的bean定义资源中获取bean定义信息并注册到容器
// 比如导入的xml或者groovy bean定义文件
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 从配置类导入的ImportBeanDefinitionRegistrar中获取bean定义信息并注册到容器
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
/**
* Register the Configuration class itself as a bean definition.
* 配置类本身作为bean定义注册到容器
*/
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(
configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,
definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
}
/**
* Read the given BeanMethod, registering bean definitions
* with the BeanDefinitionRegistry based on its contents.
* @Bean注解的配置类方法作为bean定义注册到bean容器
*/
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// Consider name and any aliases
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(
beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" +
beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method 静态@Bean方法
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method 实例成员@Bean方法
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
if (destroyMethodName != null) {
beanDef.setDestroyMethodName(destroyMethodName);
}
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
if (!this.registry.containsBeanDefinition(beanName)) {
return false;
}
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
// Is the existing bean definition one that was created from a configuration class?
// -> allow the current bean method to override, since both are at second-pass level.
// However, if the bean method is an overloaded case on the same configuration class,
// preserve the existing bean definition.
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
return ccbd.getMetadata().getClassName().equals(
beanMethod.getConfigurationClass().getMetadata().getClassName());
}
// A bean definition resulting from a component scan can be silently overridden
// by an @Bean method, as of 4.2...
if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
return false;
}
// Has the existing bean definition bean marked as a framework-generated bean?
// -> allow the current bean method to override it, since it is application-level
if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
return false;
}
// At this point, it's a top-level override (probably XML), just having been parsed
// before configuration class processing kicks in...
if (this.registry instanceof DefaultListableBeanFactory &&
!((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(
beanMethod.getConfigurationClass().getResource().getDescription(),
beanName,
"@Bean definition illegally overridden by existing bean definition: "
+ existingBeanDef);
}
if (logger.isInfoEnabled()) {
logger.info(String.format("Skipping bean definition for %s: a definition for bean '%s' " +
"already exists. This top-level bean definition is considered as an override.",
beanMethod, beanName));
}
return true;
}
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<Class<?>, BeanDefinitionReader>();
for (Map.Entry<String, Class<? extends BeanDefinitionReader>> entry : importedResources.entrySet()) {
String resource = entry.getKey();
Class<? extends BeanDefinitionReader> readerClass = entry.getValue();
// Default reader selection necessary?
if (BeanDefinitionReader.class == readerClass) {
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
// When clearly asking for Groovy, that's what they'll get...
// 如果是groovy bean定义文件采用如下读取类
readerClass = GroovyBeanDefinitionReader.class;
}
else {
// Primarily ".xml" files but for any other extension as well
// 如果是xml bean定义文件采用如下读取类
readerClass = XmlBeanDefinitionReader.class;
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
if (reader == null) {
try {
// Instantiate the specified BeanDefinitionReader
reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
// Delegate the current ResourceLoader to it if possible
if (reader instanceof AbstractBeanDefinitionReader) {
AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
abdr.setResourceLoader(this.resourceLoader);
abdr.setEnvironment(this.environment);
}
readerInstanceCache.put(readerClass, reader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}
// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
// 从导入的文件中读取bean定义并注册到bean容器
reader.loadBeanDefinitions(resource);
}
}
// 对参数中所有ImportBeanDefinitionRegistrar实例,逐一调用其方法registerBeanDefinitions()
private void loadBeanDefinitionsFromRegistrars(
Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
for (Map.Entry<ImportBeanDefinitionRegistrar, AnnotationMetadata> entry :
registrars.entrySet()) {
entry.getKey().registerBeanDefinitions(entry.getValue(), this.registry);
}
}
/**
* RootBeanDefinition marker subclass used to signify that a bean definition
* was created from a configuration class as opposed to any other configuration source.
* Used in bean overriding cases where it's necessary to determine whether the bean
* definition was created externally.
*/
@SuppressWarnings("serial")
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition
implements AnnotatedBeanDefinition {
private final AnnotationMetadata annotationMetadata;
private final MethodMetadata factoryMethodMetadata;
public ConfigurationClassBeanDefinition(ConfigurationClass configClass,
MethodMetadata beanMethodMetadata) {
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
setLenientConstructorResolution(false);
}
public ConfigurationClassBeanDefinition(
RootBeanDefinition original, ConfigurationClass configClass,
MethodMetadata beanMethodMetadata) {
super(original);
this.annotationMetadata = configClass.getMetadata();
this.factoryMethodMetadata = beanMethodMetadata;
}
private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
super(original);
this.annotationMetadata = original.annotationMetadata;
this.factoryMethodMetadata = original.factoryMethodMetadata;
}
@Override
public AnnotationMetadata getMetadata() {
return this.annotationMetadata;
}
@Override
public MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
@Override
public boolean isFactoryMethod(Method candidate) {
return (super.isFactoryMethod(candidate) && BeanAnnotationHelper.isBeanAnnotated(candidate));
}
@Override
public ConfigurationClassBeanDefinition cloneBeanDefinition() {
return new ConfigurationClassBeanDefinition(this);
}
}
/**
* 用于跟踪某个配置类是否需要被忽略
* Evaluate @Conditional annotations, tracking results and taking into
* account 'imported by'.
*/
private class TrackedConditionEvaluator {
private final Map<ConfigurationClass, Boolean> skipped = new HashMap<ConfigurationClass, Boolean>();
public boolean shouldSkip(ConfigurationClass configClass) {
Boolean skip = this.skipped.get(configClass);
if (skip == null) {
if (configClass.isImported()) {
boolean allSkipped = true;
for (ConfigurationClass importedBy : configClass.getImportedBy()) {
if (!shouldSkip(importedBy)) {
allSkipped = false;
break;
}
}
if (allSkipped) {
// The config classes that imported this one were all skipped,
// therefore we are skipped...
skip = true;
}
}
if (skip == null) {
skip = conditionEvaluator.shouldSkip(
configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN
);
}
this.skipped.put(configClass, skip);
}
return skip;
}
}
}
Spring 内部工具 : 配置类、Bean定义的发现和注册
Spring 基于注解的 bean 定义/注册方式总结
Spring 配置类的分类
Spring 工具类 ConfigurationClassParser 分析得到配置类
Spring 工具类 ClassPathBeanDefinitionScanner bean定义扫描
Spring BeanDefinitionRegistryPostProcessor : ConfigurationClassPostProcessor