Spring Boot 自动装配 源码 笔记

写这篇博客的原因

  1. 自动装配是spring boot核心功能/特点/优点

自动装配是什么

我们添加jar依赖时,spring boot自动为我们配置一些组件的相关配置,使得我们仅用少量的配置甚至是不用配置就可以直接使用组件。

思想

我们添加依赖后,spring boot通过是否包含某个组件类等方式,推断是否需要自动配置这个组件。

实现 & 源码分析

@EnableAutoConfiguration

  1. @EnableAutoConfiguration注解的含义即开启自动装配
  2. 大家可能会有疑问,自己的spring boot项目没有用到@EnableAutoConfiguration注解,为什么也可以使用自动装配功能?因为,启动类使用用了@SpringBootApplicationٖ注解,@SpringBootApplicationٖ注解是由@SpringBootConfiguration、@ComponentScan和@EnableAutoConfiguration三个注解复合而成,无需我们显式使用@EnableAutoConfiguration注解。
  3. @EnableAutoConfiguration注解是由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})两个注解复合而成
    • @AutoConfigurationPackage注解是@Import({Registrar.class})的封装
      • @Import作用是导入组件,@Import({Registrar.class})就是导入Registrar.class,
      • Registrar类将启动类所在包及其所有子包下的组件(例如@Entity)扫描到spring容器中,而@ComponentScan是扫描的@Component注解(包括其派生的注解@Controller/@Service/@Component/@Repository)
    • @Import({AutoConfigurationImportSelector.class})注解即是导入AutoConfigurationImportSelector.class

AutoConfigurationImportSelector

直译类名:自动配置导入筛选器,见名知意:将“自动配置”的配置筛选并导入到系统中,方式如下:

  • 通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类
  • 通过AutoConfigurationMetadataLoader加载META-INF/spring-autoconfigure-metadata.properties文件中自动配置类的自动装配条件
  • 自动配置类进行去重,去掉注解的排除属性排除的自动配置类,使用自动装配条件过滤自动配置类
    源码分析:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	private static class AutoConfigurationGroup
			implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
		@Override
		// 入口方法
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));
			//获取自动装配的配置
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}
	}
	
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//从配置文件加载自动装配类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//自动装配类去重
		configurations = removeDuplicates(configurations);
		//排除 我们配置的 ‘需要排除的’ 自动配置类,即:
		//    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
		//    @SpringBootApplication(excludeName ={"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
		//    等
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		
		//根据自动配置条件,过滤无需启用的自动配置类
		//  1. 通过AutoConfigurationMetadataLoader加载META-INF/spring-autoconfigure-metadata.properties文件中自动装配条件
		//    形式自动装配类.条件=值
		//    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.core.RabbitMessagingTemplate
		//    常见的自动装配条件如:某个类是否存在,某个bean是否存在,配置文件的某个配置项是否存在等
		//  2. 使用ConfigurationClassFilters过滤器链使用过滤条件过滤自动配置类
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
	
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		//通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类,如下所示
		//    # Auto Configure
		//    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
		//    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
		//    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
		//    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
		//    省略...
		//configurations中每个元素就是如org.springframework.boot.autoconfigure.aop.AopAutoConfiguration这样的自动配置类的类全名,共有100多个
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
}

启动流程中关于自动装配的步骤

  1. 启动类main方法调用SpringApplication.run(BootApplication.class, args);
@SpringBootApplication
public class BootApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class, args);
    }
}
  1. SpringApplication.run(BootApplication.class, args)经过调用链,调用到本类的实例方法run(String… args)
public class SpringApplication {
	public ConfigurableApplicationContext run(String... args) {
		//省略...
		
		ConfigurableApplicationContext context = null;
		
		//省略...

		//创建spring上下文,最终调用到ApplicationContextFactory函数式接口,
		// 如果是SERVLET应用就new AnnotationConfigServletWebServerApplicationContext()
		// 如果是REACTIVE应用就new AnnotationConfigReactiveWebServerApplicationContext()
		// 都不是则new AnnotationConfigApplicationContext()
		context = createApplicationContext();

		//省略...
		
		//创建上下文,最终会调用到AbstractApplicationContext.refresh()方法,这个方法是spring上下文初始化的核心方法
		context = createApplicationContext();
			
		//刷新上下文
		refreshContext(context);
		
		//省略...
	}
}
  1. AbstractApplicationContext.refresh(),这个方法是spring上下文启动的核心流程,也是"自动装配的总体流程"。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			//省略...

			// Tell the subclass to refresh the internal bean factory.
        	// 初始化BeanFactory-默认实现是DefaultListableBeanFactory
        	// 1. 使用SAX对xml文件进行读取,转化为Document
        	// 2. 对xml中的各种标签进行解析
        	//   2.1 如果是bean标签,将其解析为BeanDefition,并注册到容器中,一般是DefaultListableBeanFactory.beanDefinitionMap
        	//   2.2 如果是包扫描标签,则使用ComponentScanBeanDefinitionParser解析
        	//      2.2.1 解析的注解类型为:@Component及其子注解(@Repository、@Service、@Controller、@Configuration)
        	//      2.2.2 将包扫描路径转化为绝对路径,通过字节流读取包扫描路径下的.class文件
        	//      2.2.3 通过ClassReader及其他组件直接解析.class文件的内容为BeanDefition,使用asm技术按JVM规范解析.class文件
        	//      2.2.4 将上一步解析得到的BeanDefition注册到容器中,一般是DefaultListableBeanFactory.beanDefinitionMap
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			//省略...

			// Invoke factory processors registered as beans in the context.
            // invokeBeanFactoryPostProcessors()方法是执行所有BeanFactory的后置处理器
			//   * 即执行实现BeanDefinitionRegistryPostProcessor接口的实现类,
			//   * 这样就会执行到ConfigurationClassPostProcessor#processConfigBeanDefinitions()
			//   	* 直译:配置类(@Configuration注解的类)后置处理器#处理配置Bean定义信息
			//   	* 该方法委托ConfigurationClassParser#doProcessConfigurationClass()对配置Bean进行解析
			//			* 该方法可以解析@Component,@PropertySource,@ComponentScan, @Import,@ImportResource,@Bean等注解
			invokeBeanFactoryPostProcessors(beanFactory);
			
			//省略...

			// Instantiate all remaining (non-lazy-init) singletons.
            //通过BeanDefinitions初始化单例非懒加载的bean
            //  原型Bean的初始化时机:每次通过BeanFactory.getBean()时新生成一个
            //  懒加载Bean的初始化时机:延迟使用时加载
            //通过自动配置Bean实例化,完成自动配置功能
			finishBeanFactoryInitialization(beanFactory);
			
			//省略...
	}
}
  1. ConfigurationClassPostProcessor#processConfigBeanDefinitions()
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		//省略...
		// Parse each @Configuration class
		// 注解类解析器会解析每一个@Configuration注解的类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			//注解类解析器解析,会执行到ConfigurationClassParser#parse()
			parser.parse(candidates);
			//省略...
		}
		while (!candidates.isEmpty());
		//省略...
		//最终得到了注解bean定义
	}
}
  1. ConfigurationClassParser#parse()
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					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());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		//最终调用到ConfigurationClassPostProcessor.DeferredImportSelectorGrouping#getImports()
		this.deferredImportSelectorHandler.process();
	}
	
	private static class DeferredImportSelectorGrouping {
		public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
				// 调用到AutoConfigurationImportSelector.AutoConfigurationGroup#process()
				// AutoConfigurationImportSelector类我们在上面已经分析过了
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			// 调用到AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports()
			// AutoConfigurationImportSelector类我们在上面已经分析过了
			return this.group.selectImports();
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值