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详解的更多相关文章

  1. Linux的启动流程以及GRUB详解

     一.Linux引导和启动流程       概述,计算机电源接通后通过BISO之后,没有问题,就会去硬盘上找到MBR(Main Boot Record 主引导记录区)位于整个硬盘的0磁道0柱面1扇区, ...

  2. Tomcat5启动流程与配置详解

    标签:配置 tomcat 休闲 职场 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://zhangjunhd.blog.51cto. ...

  3. 2017.3.31 spring mvc教程(二)核心流程及配置详解

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  4. Spring学习 6- Spring MVC (Spring MVC原理及配置详解)

    百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...

  5. [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解

    [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装.启动及PXE理论详解 本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议 ...

  6. Spring Boot Actuator监控使用详解

    在企业级应用中,学习了如何进行SpringBoot应用的功能开发,以及如何写单元测试.集成测试等还是不够的.在实际的软件开发中还需要:应用程序的监控和管理.SpringBoot的Actuator模块实 ...

  7. DBA_Oracle Startup / Shutdown启动和关闭过程详解(概念)

    2014-08-07 Created By BaoXinjian

  8. [置顶] 深入浅出Spring(三) AOP详解

    上次的博文深入浅出Spring(二) IoC详解中,我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming ...

  9. Spring Boot的启动器Starter详解

    Spring Boot的启动器Starter详解 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs Spring Boot ...

  10. 服务启动项 Start类型详解

    注册表的服务启动项 Start类型详解 HKLM\SYSTEM\CurrentControlSet\services\ 下的服务项.不论有没有在services.msc服务管理控制台中显示,在注册表中 ...

随机推荐

  1. django+drf开发一些个人的标准化

    最近在改造一下个人的开发风格.特分享一下. 子应用我一般放在apps中,每个不同模块的子应用起不同的名字.startapp后自己移动一下,记得修改一下Appconfig中的name即可. 子应用中创建 ...

  2. 组合式api-跨层级组件通信provide和inject

    vue2的provide和inject:https://v2.cn.vuejs.org/v2/api/#provide-inject 主要作用: 跨层级传递数据(响应和非相应数据都可以).方法(函数) ...

  3. selenium之下拉菜单列表定位

    下拉菜单列表定位>>使用Select类定位 from selenium.webdriver.support.ui import Select #导入Select类 select=Selec ...

  4. DC-3

    DC-3 前言:这个DC系列去年就做完了,但是因为那时候visualbox老崩搞得头大,一直漏了DC-3没做.现在重新搞好了来完结这个系列 扫存活的主机,显示只开了80 扫了一下目录,看了几个没有什么 ...

  5. Kotlin委托属性(1)

    在Kotlin中,委托属性(Delegated Properties)是一种强大的语言特性,允许你将属性的 getter 和 setter 方法的实现委托给其他对象.这使得你能够通过委托来重用代码.将 ...

  6. JavaFx之controlsfx8下载(十七)

    JavaFx之controlsfx8下载(十七) controlsfx是JavaFx功能的扩展补充,这里我使用java8,我将源码下载下来并编译好jar,在java8的环境双击运行runSamples ...

  7. 关于Triple DES(3DES)对称加密算法

    一.引言 在网络安全领域,对称加密算法作为一种常见的加密手段,被广泛应用于保障数据传输的保密性和完整性.其中,DES(Data Encryption Standard)算法作为一种经典的对称加密算法, ...

  8. 毕业季 | 程序员初入职场必备软件开发神器,华为云Astro带你开启新篇章

    摘要:5分钟写出应用,10分钟开发大屏,新手程序员必学技能之华为云Astro,快来get. 本文分享自华为云社区<毕业季 | 程序员初入职场必备软件开发神器,华为云Astro带你开启新篇章> ...

  9. 详解GaussDB(DWS)的CPU资源隔离管控能力

    摘要:GaussDB使用cgroup实现了两种cpu管控能力,基于cpu.shares的共享配额管控和基于cpuset的专属限额管控. 本文分享自华为云社区<GaussDB(DWS)的CPU资源 ...

  10. APP违法使用个人信息?不用怕,华为云VSS为你保驾护航

    摘要:华为云VSS漏洞扫描服务移动应用安全检测,为华为云客户提供移动应用的合规检测能力,遵循工信部164号文要求,针对安卓(apk)和鸿蒙(hap)应用进行安全和隐私合规问题检测. 本文分享自华为云社 ...