spring启动流程 (3) BeanDefinition详解
BeanDefinition在Spring初始化阶段保存Bean的元数据信息,包括Class名称、Scope、构造方法参数、属性值等信息,本文将介绍一下BeanDefinition接口、重要的实现类,以及在Spring中的使用示例。
BeanDefinition接口
用于描述了一个Bean实例,该Bean实例具有属性、构造方法参数以及由具体实现提供的其他信息。
这是一个基础接口:主要目的是允许BeanFactoryPostProcessor获取和修改Bean实例属性和其他元数据。
封装以下信息:
- ParentName - The name of the parent definition of this bean definition.
- BeanClassName - The bean class name of this bean definition. The class name can be modified during bean factory post-processing, typically replacing the original class name with a parsed variant of it.
- Scope - Override the target scope of this bean, specifying a new scope name.
- isLazyInit - Whether this bean should be lazily initialized.
- DependsOn - The names of the beans that this bean depends on being initialized. The bean factory will guarantee that these beans get initialized first.
- AutowireCandidate - Whether this bean is a candidate for getting autowired into some other bean.
- Primary - Whether this bean is a primary autowire candidate.
- FactoryBeanName - The factory bean to use. This the name of the bean to call the specified factory method on.
- FactoryMethodName - Specify a factory method, if any. This method will be invoked with constructor arguments, or with no arguments if none are specified. The method will be invoked on the specified factory bean, if any, or otherwise as a static method on the local bean class.
- ConstructorArgumentValues - Constructor argument values for this bean.
- PropertyValues - The property values to be applied to a new instance of the bean.
- InitMethodName - The name of the initializer method.
- DestroyMethodName - The name of the destroy method.
- Role - The role hint for this BeanDefinition. The role hint provides the frameworks as well as tools an indication of the role and importance of a particular BeanDefinition.
- ResolvableType - A resolvable type for this bean definition, based on the bean class or other specific metadata.
- isSingleton - Whether this a Singleton, with a single, shared instance returned on all calls.
- isPrototype - Whether this a Prototype, with an independent instance returned for each call.
- isAbstract - Whether this bean is "abstract", that is, not meant to be instantiated.
- OriginatingBeanDefinition - The originating BeanDefinition.

AbstractBeanDefinition类
实现了BeanDefinition接口,具体的、完整的BeanDefinition基类,抽取出GenericBeanDefinition、RootBeanDefinition和ChildBeanDefinition的公共属性。
扩展的属性:
- AutowireMode - The autowire mode. This determines whether any automagical detection and setting of bean references will happen. Default is AUTOWIRE_NO which means there won't be convention-based autowiring by name or type (however, there may still be explicit annotation-driven autowiring).
- AUTOWIRE_NO
- AUTOWIRE_BY_NAME
- AUTOWIRE_BY_TYPE
- AUTOWIRE_CONSTRUCTOR
- AUTOWIRE_AUTODETECT
RootBeanDefinition类
继承AbstractBeanDefinition类。
RootBeanDefinition表示在运行时支持BeanFactory中指定Bean的合并BeanDefinition。它可能是由多个相互继承的原始BeanDefinition创建的,通常注册为GenericBeanDefinitions。RootBeanDefinition本质上是运行时的"统一"RootBeanDefinition视图。
RootBeanDefinition也可以用于在配置阶段注册各个BeanDefinition。然而,自Spring2.5以来,以编程方式注册BeanDefinition的首选方式是GenericBeanDefinition类。GenericBeanDefinition的优势是允许动态定义父依赖项,而不是将角色硬编码为RootBeanDefinition。
扩展的属性:
- DecoratedDefinition - Target definition that is being decorated by this bean definition.
- QualifiedElement - Specify the AnnotatedElement defining qualifiers, to be used instead of the target class or factory method.
- TargetType - Specify a generics-containing target type of this bean definition, if known in advance.
- stale - Determines if the definition needs to be re-merged.
- allowCaching
- isFactoryBean
GenericBeanDefinition类
继承AbstractBeanDefinition类。
GenericBeanDefinition是用于构建标准BeanDefinition的一站式组件。与其他BeanDefinition一样,它允许指定一个类以及可选的构造方法参数和属性。另外,从父BeanDefinition派生可以通过parentName属性灵活配置。
通常,使用GenericBeanDefinition类来注册用户可见的BeanDefinition,后置处理器可能会对其进行操作,甚至可能重新配置parentName属性。如果父子关系恰好是预先确定的,请使用RootBeanDefinition和ChildBeanDefinition。
AnnotatedBeanDefinition接口
继承BeanDefinition接口。
扩展BeanDefinition接口,提供Bean的AnnotationMetadata,而不需要加载该类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
*/
MethodMetadata getFactoryMethodMetadata();
}
ScannedGenericBeanDefinition类
GenericBeanDefinition类的扩展,基于ASM ClassReader,实现了AnnotatedBeanDefinition接口,可以获取注解元数据。
这个类不会提前加载Bean Class。它从.class文件检索所有相关的元数据,并使用ASM ClassReader进行解析。
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
/**
* Create a new ScannedGenericBeanDefinition for the class that the
* given MetadataReader describes.
* @param metadataReader the MetadataReader for the scanned target class
*/
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
AnnotatedGenericBeanDefinition类
GenericBeanDefinition类的扩展,实现了AnnotatedBeanDefinition接口,可以获取注解元数据。
public class AnnotatedGenericBeanDefinition
extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
private MethodMetadata factoryMethodMetadata;
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
} else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
public AnnotatedGenericBeanDefinition(
AnnotationMetadata metadata,
MethodMetadata factoryMethodMetadata) {
this(metadata);
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
Spring中使用BeanDefinition示例
注册componentClasses
AnnotationConfigApplicationContext启动代码:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ServiceConfig.class);
applicationContext.refresh();
AnnotationConfigApplicationContext在启动时可以使用register方法注册@Configuration类,本小节将从这个方法入手看一个BeanDefinition的使用示例:
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
// reader.register(...)
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
private <T> void doRegisterBean(Class<T> beanClass, String name,
Class<? extends Annotation>[] qualifiers, Supplier<T> supplier,
BeanDefinitionCustomizer[] customizers) {
// 构造方法中会解析AnnotationMetadata元数据
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 判断是否允许装配
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 解析Lazy,Primary,DependsOn,Role等属性
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
} else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
} else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 处理Scope的proxyMode
definitionHolder = AnnotationConfigUtils
.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册到容器
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
// BeanDefinitionReaderUtils.registerBeanDefinition(...)
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 将Bean注册到BeanDefinitionRegistry
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
此处的registry是AnnotationConfigApplicationContext对象,registerBeanDefinition方法的实现在GenericApplicationContext类:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
// beanFactory.registerBeanDefinition(...)
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
} else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
} else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
@Bean注解
@Bean注解注入的Bean最终在ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsForBeanMethod方法注册BeanDefinition:
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;
}
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// Consider name and any aliases
List<String> names = new ArrayList<>(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)) {
return;
}
// 创建ConfigurationClassBeanDefinition
// 是RootBeanDefinition的子类
ConfigurationClassBeanDefinition beanDef =
new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(
((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
} else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
} else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
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, beanName);
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
@ComponentScan注解
支持@ComponentScan注解的最终逻辑在ClassPathScanningCandidateComponentProvider类的scanCandidateComponents方法中:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
// 此处获取到的是SimpleMetadataReader对象,
// 内部使用ASM解析.class文件封装AnnotationMetadata对象
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 判断是一个Component
if (isCandidateComponent(metadataReader)) {
// 创建ScannedGenericBeanDefinition对象
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
spring启动流程 (3) BeanDefinition详解的更多相关文章
- Linux的启动流程以及GRUB详解
一.Linux引导和启动流程 概述,计算机电源接通后通过BISO之后,没有问题,就会去硬盘上找到MBR(Main Boot Record 主引导记录区)位于整个硬盘的0磁道0柱面1扇区, ...
- Tomcat5启动流程与配置详解
标签:配置 tomcat 休闲 职场 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://zhangjunhd.blog.51cto. ...
- 2017.3.31 spring mvc教程(二)核心流程及配置详解
学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...
- Spring学习 6- Spring MVC (Spring MVC原理及配置详解)
百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...
- [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解
[PXE] Linux(centos6)中PXE 服务器搭建,PXE安装.启动及PXE理论详解 本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议 ...
- Spring Boot Actuator监控使用详解
在企业级应用中,学习了如何进行SpringBoot应用的功能开发,以及如何写单元测试.集成测试等还是不够的.在实际的软件开发中还需要:应用程序的监控和管理.SpringBoot的Actuator模块实 ...
- DBA_Oracle Startup / Shutdown启动和关闭过程详解(概念)
2014-08-07 Created By BaoXinjian
- [置顶] 深入浅出Spring(三) AOP详解
上次的博文深入浅出Spring(二) IoC详解中,我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming ...
- Spring Boot的启动器Starter详解
Spring Boot的启动器Starter详解 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs Spring Boot ...
- 服务启动项 Start类型详解
注册表的服务启动项 Start类型详解 HKLM\SYSTEM\CurrentControlSet\services\ 下的服务项.不论有没有在services.msc服务管理控制台中显示,在注册表中 ...
随机推荐
- C++ Qt开发:StandardItemModel数据模型组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍Standar ...
- URL路径参数转换器
作用和基本使用 作用: 用于校验请求的路由参数中的值是否符合符合指定的规则. 这个使用方法和django中的路由参数转换器是差不多的. 至于为什么用路径参数转换器,原因和django中的一样,虽然你可 ...
- Android辅助功能
1:AccessibilityService 新建service public class AccessibilityService extends android.accessibilityserv ...
- LLaMA大型语言模型
LLaMA (Large Language Model Meta AI)是Meta公司发布的大型语言模型系列,近日LLaMA种子文件被合并到了GitHub 上,同时一些项目维护者给予了批准,目前该项目 ...
- ElasticSearch之Exists API
检查指定名称的索引是否存在. 命令样例如下: curl -I "https://localhost:9200/testindex_002?pretty" --cacert $ES_ ...
- Python——第三章:内置函数(上)
Python中的内置函数 基础数据类型相关(38) 和数字相关(14) 数字类型(4) bool--布尔型 int--整型 float--浮点型 complex--虚数 机制转换(3) bin--二进 ...
- ajax与thymeleaf分别实现数据传输
小杰笔记篇: 1:第一种:利用Model和thymeleaf引擎来完成: Controller层: @CrossOrigin//解决跨域问题 @Controller public class User ...
- 《RAPL: A Relation-Aware Prototype Learning Approach for Few-Shot Document-Level Relation Extraction》阅读笔记
代码 原文地址 预备知识: 1.什么是元学习(Meta Learning)? 元学习或者叫做"学会学习"(Learning to learn),它是要"学会如何学 ...
- Luogu1419 区间问题 二分 单调优化
原题链接 题意 给定一段长度为1e5的序列A,并且给我们一个范围 \([S, T]\), 要求我们求出一段长度在这个范围内的连续子序列,并且要使这个连续子序列的平均值最大,输出这个平均值. 思路 一开 ...
- cf1453F 二维DP 思维
cf1453F 二维DP 思维 原题链接 题意 目前我们有一个序列,在第i个点可以走到[i + 1, i + a[i]]区间内的任意一点(也就是说如果a[i]是0,路就走不通了) 现在要求我们将一些位 ...