SpringBoot学习笔记(三) 自动装配原理

继SpringBoot学习笔记(二) 整合redis+mybatis+Dubbo,本篇文章我们开始分析SpringBoot的自动装配原理。

概述

前面已经介绍了Spring的加载过程,经历扫描配置文件--收集beanName--实例化bean这几步,SpringBoot同样如此,源于Spring,高于Spring,省去了”简单模式(特殊场景如多数据源引入,需要额外的单独配置)下xml配置文件的繁琐过程。下面让我们来揭秘SpringBoot的自动装配原理。

源码解读

1.先从run方法进入,

public class DemoApplication {

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

2.进入到run方法中

public static ConfigurableApplicationContext run(Class primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

3.最后点到这里

SpringBoot学习笔记(三) 自动装配原理_第1张图片

4.继续深入

private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh((ApplicationContext)context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
                ;
            }
        }

    }

5.进入到refresh

protected void refresh(ConfigurableApplicationContext applicationContext) {
        applicationContext.refresh();
    }

6.继续进入方法

org.springframework.context.support.AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);  //看这里
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

7.进入到invokeBeanFactoryPostProcessors方法内部

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //这里
       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {

     sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            // 这里
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
}

8.继续进入

private static void invokeBeanDefinitionRegistryPostProcessors(Collection postProcessors, BeanDefinitionRegistry registry) {
        Iterator var2 = postProcessors.iterator();

        while(var2.hasNext()) {
            BeanDefinitionRegistryPostProcessor postProcessor = (BeanDefinitionRegistryPostProcessor)var2.next();
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }

    }

9.进入到postProcessor.postProcessBeanDefinitionRegistry(registry)方法

SpringBoot学习笔记(三) 自动装配原理_第2张图片

10.看这里

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);
        } else if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
        } else {
            this.registriesPostProcessed.add(registryId);
            this.processConfigBeanDefinitions(registry);
        }
    }

11.看最后一句this.processConfigBeanDefinitions(registry) 进入该方法

调试程序发现

这里有我们熟悉的RedisTemplateAutoConfiguration类

并且在上一步中

SpringBoot学习笔记(三) 自动装配原理_第3张图片

就已经读读出了配置类。

这里注意:

configClasses获取的是starts中依赖的组件,用rabbitmq举例,组件中如果不对其进行引用那么config中是没有相关类信息的,相反,如果对rabbitmq进行引用则可以加载。

 

============以下是分析如何从spring.factories中加载XXXAutoConfigration的过程============

12.继续,configClasses的具体读取应该是在parser.parse(candidates)

进入方法中

public void parse(Set configCandidates) {
        Iterator var2 = configCandidates.iterator();

        while(var2.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
            BeanDefinition bd = holder.getBeanDefinition();

            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
                } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                    this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
                } else {
                    this.parse(bd.getBeanClassName(), holder.getBeanName());
                }
            } catch (BeanDefinitionStoreException var6) {
                throw var6;
            } catch (Throwable var7) {
                throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
            }
        }

        this.deferredImportSelectorHandler.process();
    }

13.随便点到一个this.parse方法中

protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) throws IOException {
        if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
            if (existingClass != null) {
                if (configClass.isImported()) {
                    if (existingClass.isImported()) {
                        existingClass.mergeImportedBy(configClass);
                    }

                    return;
                }

                this.configurationClasses.remove(configClass);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }

            ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);

            do {
                // 点这里
                sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
            } while(sourceClass != null);

            this.configurationClasses.put(configClass, configClass);
        }
    }

 14.this.doProcessConfigurationClass(configClass, sourceClass, filter);

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
      		// 在这递归的,会回到上一步代码中
			processMemberClasses(configClass, sourceClass, filter);
		}


		// Process any @Import annotations
  		// 看这个名字可以知道这个方法的作用
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
	}

getImports(sourceClass)方法是一个递归调用,用来收集Import注解。

15.继续看processImports方法

org.springframework.context.annotation.ConfigurationClassParser#processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection importCandidates, Predicate exclusionFilter,
			boolean checkForCircularImports) {
		...
		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate selectorFilter = selector.getExclusionFilter();

						if (selector instanceof DeferredImportSelector) {
              				// 因为AutoConfigurationImportSelector继承了DeferredImportSelector,所以会进入这个方法,放到
              				// 列表里处理,直接放到一个List中。
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
					}
        }
        ...
			}
		}
	}

16.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler#handle

public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			if (this.deferredImportSelectors == null) {
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				handler.register(holder);
				handler.processGroupImports();
			}
			else {
				this.deferredImportSelectors.add(holder);
			}
		}

17.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#register代码

public void register(DeferredImportSelectorHolder deferredImport) {
      // AutoConfigurationImportSelector返回的是AutoConfigurationGroup.class,代码中已写死
			Class group = deferredImport.getImportSelector().getImportGroup();
      // 封装成 DeferredImportSelector.Group 对象,并放到了groupings中,groupings是LinkedHashMap
      // Group对象是用AutoConfigurationGroup.class生成
			DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
					(group != null ? group : deferredImport),
					key -> new DeferredImportSelectorGrouping(createGroup(group)));
			grouping.add(deferredImport);
			this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}

18.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports方法,SpringSPI的调用点=

public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate exclusionFilter = grouping.getCandidateFilter();
        //遍历放入到grouping中的group,并执行getImports()方法,此方法就是SPI调用点!!!!
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
						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);
					}
				});
			}
		}

19.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports 方法

public Iterable getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            // 调用group的process方法
		    this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
		}

20.org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process

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()));
           // 调用getAutoConfigurationEntry
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

如上所示,最终来到

21.org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry

该方法可以从spring.factories读取相应配置。

============以上是分析如何从spring.factories中加载XXXAutoConfigration的过程============

好,我们继续。

============以下是将configClasses中的XXXAutoConfigration注册为Bean的过程============

22.回到步骤11.org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

public void loadBeanDefinitions(Set configurationModel) {
        ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator = new ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator();
        Iterator var3 = configurationModel.iterator();

        while(var3.hasNext()) {
            ConfigurationClass configClass = (ConfigurationClass)var3.next();
            this.loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }

    }

23.org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) {
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            // 此处打上断点configClass.getResource().toString().contains("Rabbit")
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }

            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        } else {
            // 此处打上断点configClass.getResource().toString().contains("Rabbit")
            if (configClass.isImported()) {
                this.registerBeanDefinitionForImportedConfigurationClass(configClass);
            }

            Iterator var3 = configClass.getBeanMethods().iterator();
            
            while(var3.hasNext()) {
                BeanMethod beanMethod = (BeanMethod)var3.next();
                //这里处理对应的@Bean方法 !!!!!!!!!!!!!!!!!!!!
                this.loadBeanDefinitionsForBeanMethod(beanMethod);
            }

            this.loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
            this.loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
        }
    }

执行完this.registerBeanDefinitionForImportedConfigurationClass(configClass);看目前的BeanNames

SpringBoot学习笔记(三) 自动装配原理_第4张图片

24.继续org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        
                //注册
                this.registry.registerBeanDefinition(beanName, beanDefToRegister);
        
    }

SpringBoot学习笔记(三) 自动装配原理_第5张图片

注册完成以后效果

SpringBoot学习笔记(三) 自动装配原理_第6张图片

============以上是将configClasses中的XXXAutoConfigration注册为Bean的过程============

可以看到,不仅RabbitAutoConfiguration中的RabbitConnectionFactoryCreator成功注册,rabbitconnectionFactory也进行了注册(rabbitConnectionFactory的注册时机在哪里困扰了博主很久,在这里恍然大悟)。

实例化具体过程参考: Spring源码解析(五)IOC源码

以上就是SpringBoot自动装配的全部过程。

 

你可能感兴趣的:(#,SpringBoot)