返回顶部
首页 > 资讯 > 后端开发 > Python >浅析SpringBoot自动装配的实现
  • 227
分享到

浅析SpringBoot自动装配的实现

2024-04-02 19:04:59 227人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录背景解析起始具体解析结论备注背景 众所周知,如下即可启动一个最简单的spring应用。查看@SpringBootApplication注解的源码,发现这个注解上有一个重要的注解@

背景

众所周知,如下即可启动一个最简单的spring应用。查看@SpringBootApplication注解的源码,发现这个注解上有一个重要的注解@EnableAutoConfiguration,而这个注解就是SpringBoot实现自动装配的基础


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

@EnableAutoConfiguration

EnableAutoConfiguration注解上通过@Import引入了两个类,org.springframework.boot.autoconfigure.AutoConfigurationImportSelectororg.springframework.boot.autoconfigure.AutoConfigurationPackages.ReGIStrar。通过@Import标注的类,会在解析@Import所在的配置类时,将标注类引入容器解析,并进行注册。

有众多的组件都是通过在配置类上加@EnableAutoConfiguration注解将组件引入的

  • ImportBeanDefinitionRegistrar实现了org.springframework.context.annotation.ImportBeanDefinitionRegistrarorg.springframework.boot.context.annotation.DeterminableImports
  • AutoConfigurationImportSelector实现了org.springframework.context.annotation.DeferredImportSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ....
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
    ...
}

解析

起始

通过BeanFactoryPostProcessor对需要注册的Bean进行解析。即org.springframework.context.support.AbstractApplicationContext#refresh,在AbstractApplicationContext#invokeBeanFactoryPostProcessors方法调用时,就开始了对服务配置bean的解析,为对象的生成做准备

 @Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			...

			try {
				...
                    
				invokeBeanFactoryPostProcessors(beanFactory);
			}
			catch (BeansException ex) {
			finally {
		}
	}

具体解析

调用org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors,通过获取到的BeanFactoryPostProcessor实现类对各种配置类进行解析,具体的BeanFactoryPostProcessor解析后面我们在具体分析。

这里有一个很重要的类org.springframework.context.annotation.ConfigurationClassPostProcessor,首先会调用postProcessBeanDefinitionRegistry方法

// ConfigurationClassPostProcessor类部门源码

	
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
					"postProcessBeanFactory already called on this post-processor against " + registry);
		this.registriesPostProcessed.add(registryId);
	
                // 处理配置类
		processConfigBeanDefinitions(registry);
	}
	 * Build and validate a configuration model based on the registry of
	 * {@link Configuration} classes.
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		...
		// Parse each @Configuration class
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
                // confiGCandidates为待解析的Configuration类,如配置了@SpringBootApplication的类
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
                        // 开始解析
			parser.parse(candidates);
			parser.validate();
			...
		while (!candidates.isEmpty());

通过源码可知,具体的解析操作是在org.springframework.context.annotation.ConfigurationClassParser类中

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
                                        // 将配置类进行解析。以当前配置类为原配置类,解析@PropertySource、@ComponentScan、@Import、@ImportResource、					 
                                        // @Bean等标注的类或方法,生成对应的
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
			}
			...
		}

   		// 解析通过@Import引入的配置类,自动配置类的解析也在于此
		this.deferredImportSelectorHandler.process();
	}
	public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
                                // grouping.getImports()方法获取到了所有配置的可用自动配置类,然后遍历,以配置类原点又开始一轮解析。自动装配就是在此处
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
                                                // import的解析
						processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
								Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
								exclusionFilter, false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
				});

通过DeferredImportSelectorGrouping.getImports()方法解析。在org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry方法中开始了autoConfiguration的解析。


	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
                // 解析@EnableAutoConfiguration注解中的属性exclude、excludeName
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
                // 使用SpringFactoriesLoader获取META-INF/spring.properties中配置的EnableAutoConfiguration实现类,获取所有配置的自动装配类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
                // 去重
		configurations = removeDuplicates(configurations);
                // 获取需要排除的自动装配类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
                //getConfigurationClassFilter()方法就是获取spring.factories中配置的AutoConfigurationImportFilter实现类。然后调用filter		//法对自动装配类进行有效性校验
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

再继续看org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.ConfigurationClassFilter#filter

List<String> filter(List<String> configurations) {
			long startTime = System.nanoTime();
			String[] candidates = StringUtils.toStringArray(configurations);
			boolean skipped = false;
			for (AutoConfigurationImportFilter filter : this.filters) {
                                // autoConfigurationMetadata为通过META-INF/spring-autoconfigure-metadata.properties配置文件的内容
                                // 使用filter及autoConfigurationMetadata对candidates进行校验
				boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
				for (int i = 0; i < match.length; i++) {
					if (!match[i]) {
						candidates[i] = null;
						skipped = true;
					}
				}
			}
			if (!skipped) {
				return configurations;
			}
        	...
			return result;
		}

再继续看match方法,org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition#match

@Override
	public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
                // 抽象方法,不同的filter进行不同的处理。这里会获取每一个自动装配类的条件判断情况
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
			match[i] = (outcomes[i] == null || outcomes[i].isMatch());
			if (!match[i] && outcomes[i] != null) {
				loGoutcome(autoConfigurationClasses[i], outcomes[i]);
				if (report != null) {
					report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
				}
			}
		}
		return match;
	}

通过match方法,经过多种filter的过滤,返回的就是每一个自动配置类是否可用

结论

  • SpringBoot项目有一个子项目org.springframework.boot:spring-boot-autoconfigure:xx,这个子项目主要就是做自动装配的。SpringBoot提前配置了众多已经实现自动配置功能的配置类(org.springframework.boot.autoconfigure.EnableAutoConfiguration接口的实现类)。当容器启动的时候,通过 SpringFactoriesLoader将配置类加载进容器中
  • 启动中,容器通过BeanFactoryPostProcessor接口解析、修改对象的定义。有一个很重要的配置解析实现类org.springframework.context.annotation.ConfigurationClassPostProcessor,用来解析项目中标注@Configuration 的类
  • 在进行配置类解析时(即解析配置了@SpringBootApplication注解的类),需要经过解析类的 @PropertySource@ComponentScan@Import@ImportResource@Bean、接口默认实现、父类等(org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass)。对于自动装配来说,最重要的就是解析@Import
  • 通过@Import引入了org.springframework.boot.autoconfigure.AutoConfigurationImportSelector,在进行解析@Import引入的配置类时,org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry获取到所有配置的自动装配类(通过META-INF/spring.factories文件配置EnableAutoConfiguration实现类),通过org.springframework.context.annotation.Condition定义过滤器,判断自动装配置是否需要自动装配。默认的过滤器有OnClassConditionOnWEBApplicationConditionOnBeanCondition,对应常见的condition注解ConditionalOnClassConditionalOnBean@ConditionalOnWebApplication
  • 通过过滤判断,将需要自动配置的类进行configuration解析,从而将需要配置的类转换成对应的BeanDefinition进行注册

备注

  • SpringBoot将自动装配类及过滤条件通过配置文件的形式放在了META-INF目录下,META-INF/spring.factoriesMETA-INF/spring-autoconfigure-metadata.properties
  • BeanFactoryPostProcessor进行调用时,有两种处理。首先是通过BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry解析更多的BeanDefinition,在这里就包含了所有标注类的扫描解析,自动装配类的解析,自动装配类引入类的解析。在进行BeanFactoryPostProcessor#postProcessBeanFactory调用,进行CGLIB-enhanced配置类。这里最重要的一个类就是org.springframework.context.annotation.ConfigurationClassPostProcessor,以下为此类的继承关系

到此这篇关于SpringBoot是如何做到自动装配的的文章就介绍到这了,更多相关SpringBoot自动装配内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 浅析SpringBoot自动装配的实现

本文链接: https://lsjlt.com/news/139962.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 浅析SpringBoot自动装配的实现
    目录背景解析起始具体解析结论备注背景 众所周知,如下即可启动一个最简单的Spring应用。查看@SpringBootApplication注解的源码,发现这个注解上有一个重要的注解@...
    99+
    2024-04-02
  • 浅谈SpringBoot实现自动装配的方法原理
    目录1. 什么是自动装配2. 自动装配的原理3. 自动装配的步骤4. 自定义自动配置5.代码案例总结1. 什么是自动装配 在传统的Spring框架中,我们需要手动配置和管理Bean的...
    99+
    2023-05-20
    SpringBoot实现自动装配 SpringBoot自动装配
  • 浅谈springboot自动装配原理
    目录一、SpringBootApplication二、案例三、Condition四、案例升级五、小结一、SpringBootApplication @Target(Element...
    99+
    2024-04-02
  • 深入浅析SpringBoot自动配置原理
    SpringBoot2.3.1版本源码 一、SpringBoot启动的时候加载主配置类,通过@EnableAutoConfiguration注解开启了自动配置功能 。 二...
    99+
    2024-04-02
  • SpringBoot自动装配Condition的实现方式
    目录1. 简介2. 定义2.1 @Conditional2.2 Condition3. 使用说明3.1 创建项目3.2 测试3.3 小结4. 改进4.1 创建注解4.2 修改User...
    99+
    2024-04-02
  • SpringBoot中怎么实现自动装配
    Spring Boot 实现自动装配主要通过使用 @EnableAutoConfiguration 注解和 @SpringBootA...
    99+
    2024-03-07
    SpringBoot
  • springBoot的自动装配
    springboot的自动装配实际上就是为了从spring.factories文件中获取到对应的需要进行自动装配的类,并生成相应的Bean对象,然后将它们交给spring容器来帮我们进行管理。 它的原理: 1,注解 @SpringBootA...
    99+
    2023-09-13
    spring boot spring java
  • SpringBoot详细分析自动装配原理并实现starter
    目录约定优于配置自动装配手写一个starter组件约定优于配置 SpringBoot的预定优于配置主要体现在以下几个方面: maven的目录结构: 配置文件默认存放在resource...
    99+
    2024-04-02
  • Springboot自动装配
    一.自动装配 自动装配是springboot的核心,一般提到自动装配就会和springboot联系在一起。实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进...
    99+
    2023-09-14
    spring boot java 自动装配
  • Springboot框架实现自动装配详解
    目录序言从程序的使用去入手分析序言 springboot框架价值,可以简单快速的构建独立的spring生产级别应用。springboot主要有以下的特性: 1.创建独立的Spring...
    99+
    2024-04-02
  • SpringBoot自动装配的原理详解分析
    目录前言自动装配案例自动装配分析自动装配总结前言 关于 ​​SpringBoot​​​ 的自动装配功能,相信是每一个 ​​Java​​ 程序员...
    99+
    2022-11-13
    SpringBoot 自动装配原理 SpringBoot 自动装配
  • 全面解析SpringBoot自动配置的实现原理
    之前一直在用SpringBoot框架,一直感觉SpringBoot框架自动配置的功能很强大,但是并没有明白它是怎么实现自动配置的,现在有空研究了一下,大概明白了SpringBoot框架是怎么实现自动配置的功能,我们编写一个最简单的自动配置功...
    99+
    2023-05-31
    spring boot 配置
  • SpringBoot自动装配原理以及分析
    目录先看看SpringBoot的主配置类先看看@SpringBootConfiguration注解再进去看看@Configuration先看看@AutoConfigurationPa...
    99+
    2022-11-21
    SpringBoot自动装配原理 SpringBoot自动装配 自动装配原理
  • Springboot自动装配之注入DispatcherServlet的实现方法
    原理概述 Springboot向外界提供web服务,底层依赖了springframework中的web模块(包含但不限于spring mvc核心类DispatcherServlet)...
    99+
    2024-04-02
  • SpringBoot中怎么自动装配Condition的实现方式
    这篇文章将为大家详细讲解有关SpringBoot中怎么自动装配Condition的实现方式,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1. 简介@Conditional注解在Spring4...
    99+
    2023-06-20
  • Springboot自动装配之注入DispatcherServlet怎么实现
    这篇文章主要介绍“Springboot自动装配之注入DispatcherServlet怎么实现”,在日常操作中,相信很多人在Springboot自动装配之注入DispatcherServlet怎么实现问题上存在疑惑,小编查阅了各式资料,整理...
    99+
    2023-06-30
  • SpringBoot自动配置如何实现
    这篇文章主要介绍“SpringBoot自动配置如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot自动配置如何实现”文章能帮助大家解决问题。springboot如何实现在之前的...
    99+
    2023-06-30
  • SpringBoot自动配置Quartz的实现步骤
    目录1. 依赖信息 1.1 原依赖信息 1.2 新的依赖 1.3 依赖变化 2. 新的依赖使用 2.1 默认配置可用 2.2 使用自动配置 2.3 配置信息: 3. 总结 Sprin...
    99+
    2024-04-02
  • SpringBoot如何实现Tomcat自动配置
    目录准备工作 启动 接着往下看 目录 准备工作 我们知道SpringBoot的自动装配的秘密在 org.springframework.boot.autoconfigure 包下的...
    99+
    2024-04-02
  • SpringBoot自动配置的原理分析
    这篇文章主要介绍了SpringBoot自动配置的原理分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot自动配置的原理分析文章都会有所收获,下面我们一起来看看吧。初始化一个Springboot...
    99+
    2023-06-08
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作