spring启动流程 (3) BeanDefinition详解

这篇具有很好参考价值的文章主要介绍了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.

spring启动流程 (3) 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方法中:文章来源地址https://www.toymoban.com/news/detail-517537.html

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详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring启动流程 (6完结) springmvc启动流程

    SpringMVC的启动入口在SpringServletContainerInitializer类,它是ServletContainerInitializer实现类(Servlet3.0新特性)。在实现方法中使用WebApplicationInitializer创建ApplicationContext、创建注册DispatcherServlet、初始化ApplicationContext等。 SpringMVC已经将大部分的启动逻辑封装在了几个抽象WebApplicationInitia

    2024年02月16日
    浏览(30)
  • Spring IOC 之加载 BeanDefinition

    🎬作者简介:大家好,我是小徐🥇 ☁️博客首页:CSDN主页 小徐的博客 🌄每日一句: 好学而不勤非真好学者 前面的文章我们已经对IOC之Spring统一资源加载策略有了一定的了解,本文我们将探讨Spring IOC 加载 BeanDefinition的整个过程。 我们先先看一段熟悉的代码: 这段代码是

    2024年01月17日
    浏览(30)
  • 119、Spring容器启动流程是怎样的(配有Spring启动完整流程图)

    在创建Spring容器,也就是启动Spring时: 首先会进行扫描,扫描得到所有的BeanDefinition对象,并存在一个Map中 然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多例Bean不需要在启动过程中去进行创建,对于多例Bean会在每次获取Bean时利用BeanDefinition去创建 利用BeanDefinit

    2024年02月14日
    浏览(30)
  • spring启动流程 (1) 流程概览

    本文将通过阅读AnnotationConfigApplicationContext源码,分析Spring启动流程。 核心的启动逻辑都在refresh方法中。 定义了多个register方法,用于向Spring容器注册BeanDefinition。 在创建AnnotatedBeanDefinitionReader时,会向容器注册几个注解驱动处理器: org.springframework.context.annotation.internalConf

    2024年02月11日
    浏览(29)
  • spring启动流程 (2) Bean实例化流程

    本文通过阅读Spring源码,分析Bean实例化流程。 上一篇文章已经介绍,Bean实例化入口在AbstractApplicationContext类的finishBeanFactoryInitialization方法: 返回指定beanName的(原始)单例对象,如果没有则创建一个新对象: 创建Bean实例、填充属性、调用后置处理器等:

    2024年02月11日
    浏览(68)
  • Spring高手之路12——BeanDefinitionRegistry与BeanDefinition合并解析

       BeanDefinitionRegistry 是一个非常重要的接口,存在于 Spring 的 org.springframework.beans.factory.support 包中,它是 Spring 中注册和管理 BeanDefinition 的核心组件。   让我们回顾一下上一篇说的 BeanDefinition 。在 Spring 中,一个 Bean 就是一个被 Spring 管理的对象,而一个 BeanDefinition 则是

    2024年02月13日
    浏览(30)
  • Spring高手之路11——BeanDefinition解密:构建和管理Spring Beans的基石

       BeanDefinition 是 Spring 中一个非常重要的概念,它包含了 Spring 容器用于创建、配置 Bean 所需的所有信息。理解 BeanDefinition 可以帮助我们深入掌握 Spring 的内部工作机制。 首先,让我们来对 BeanDefinition 有一个整体的认识。   对于理解 Spring 框架的概念和组件, Spring 的官方

    2024年02月15日
    浏览(37)
  • Spring Boot 启动流程

    加载配置 Spring Boot在启动时会加载应用程序的配置文件(例如application.properties或application.yml),并将其转化为内部的配置对象。 创建应用程序上下文 Spring Boot会创建一个应用程序上下文(ApplicationContext),它是Spring框架的核心容器。应用程序上下文负责管理Bean的生命周期和

    2024年02月06日
    浏览(36)
  • 【Spring专题】Spring之Bean的生命周期源码解析——上(扫描生成BeanDefinition)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析——引导篇【学习难度: ★★☆☆☆ 】

    2024年02月13日
    浏览(30)
  • Spring Boot启动流程简析

    文章首发地址 可以穿件独立的Spring应用程序,可以创建可执行的jars 内嵌tomcat或jetty等Servlet容器 提供“入门”依赖项,以简化构建配置。尽可能自动配置Spring和第三方库 提供可用于生产的功能,例如指标、运行状况检查和外部化配置 了解基本的启动注解 AnnotationUtil.java,该

    2024年02月16日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包