【微服务】SpringBoot启动流程初始化OpenFeign的入口

目录

一、前言

二、初始化OpenFeign的入口

1、ImportBeanDefinitionRegistrar接口

2、分岔路口你该往哪走

3、将ImportBeanDefinitionRegistrar添加到configurationClasses

3.1、getImports(sourceClass)

3.2、processImports()

4、Bean定义注册入口

4.1、loadBeanDefinitions()逻辑

4.2、loadBeanDefinitionsForConfigurationClass()逻辑

4.3、loadBeanDefinitionsFromRegistrars()逻辑

4.4、ImportBeanDefinitionRegistrar接口的registerBeanDefinitions()逻辑


一、前言

    学过SpringCloud的都知道使用OpenFeign都要在SpringBoot启动类上面加上@EnableFeignClients这个注解,而这个注解内部也使用了@Import注解导入FeignClientsRegistrar.class,是ImportBeanDefinitionRegistrar的实现类。

    那么会不会也跟前面讲解的SpringBoot自动装配一样呢?感觉是一样,又好像不一样,@EnableFeignClients是spring-cloud-openfeign提供的注解,里里外外都没有使用到SpringBoot的东西,但是用到了Spring的ImportBeanDefinitionRegistrar等接口。那么答案究竟是什么,下面将一一解开。

借用一下之前Bean定义注册流程图,具体的可自行去画一下。 

二、初始化OpenFeign的入口

    注意:一部分流程在前面已经讲解,这里不会过多赘述。重点讲解Spring中的ImportBeanDefinitionRegistrar接口及其涉及的一些流程。

1、ImportBeanDefinitionRegistrar接口

public interface ImportBeanDefinitionRegistrar {

	/**
	 * 根据导入@Configuration 类的给定注释元数据,根据需要注册 bean 定义。
	 *
	 * 

* 注意,由于与@Configuration 类处理相关的生命周期约束,BeanDefinitionRegistryPostProcessor 类型 * 可能 < em > 不 在这里注册。 * *

* 默认实现委托给 # registerBeanDefinition(AnnotationMetadata,BeanDefinitionRegistry)。 */ default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } /** * Register bean definitions as necessary based on the given annotation metadata of * the importing {@code @Configuration} class. *

Note that {@link BeanDefinitionRegistryPostProcessor} types may not be * registered here, due to lifecycle constraints related to {@code @Configuration} * class processing. *

The default implementation is empty. * @param importingClassMetadata annotation metadata of the importing class * @param registry current bean definition registry */ default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }

    Spring在处理ImportBeanDefinitionRegistrar接口时像处理@Configuration注解一样,那么之前的Bean定义注册文章读者可知道走的是哪个流程了。

    ImportBeanDefinitionRegistrar接口翻译过来就是“导入Bean定义登记员”,那么它的方法就是处理登记的,并且登记的是一批Bean定义。那么具体的逻辑就交给它的实现类去实现相应细节。从接口方法的两个参数,可发现登记员会不会把最终的登记委托BeanDefinitionRegistry的方法做真正的登记呢。在之前的文章确实是这样的,登记处在(BeanDefinitionRegistry的实现类)DefaultListableBeanFactorybeanDefinitionMap字段中。

    ImportBeanDefinitionRegistrar 通常和@Import注解配合使用,@Import注解将ImportBeanDefinitionRegistrar的实现类注入到@Import所属根类的ConfigurationClass属性中,在注册跟类的BeanDefinition时,会遍历调用其@Import的所有ImportBeanDefinitionRegistrar接口的 registerBeanDefinitions()方法。

2、分岔路口你该往哪走

    虽然说ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry(registry)内部会处理两大类Bean定义,调用this.reader.loadBeanDefinitions(configClasses)处理@Configuration下的Bean定义,但是调用前需要获取configClasses这个集合。故需要进到ConfigurationClassParser#parse()解析启动类这个逻辑,解析后才能获取configClasses去处理Bean定义注册。下面就是围绕这两大方向去讲解的。

3、将ImportBeanDefinitionRegistrar添加到configurationClasses

跟进ConfigurationClassParser#parse()进入到doProcessConfigurationClass()核心方法。内部有个处理任何@Import注释的processImports()方法,SpringBoot自动装配文章中也已经讲过了,这里补充一下。

3.1、getImports(sourceClass)

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第1张图片

可见processImports()中的getImports(sourceClass)内部调用的collectImports()解析启动类中用到的注解,就把@Import中的类添加到imports集合(详细SpringBooot自动装配已讲解)。其中就有FeignClientRegistrar

3.2、processImports()

	private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection importCandidates, Predicate exclusionFilter,
			boolean checkForCircularImports) {

		if (importCandidates.isEmpty()) {
			return;
		}

		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 类是它的 ImportSelector-> 委托,用于确定导入
						// EnableDiscoveryClientImportSelector、AutoConfigurationImportSelector
						Class candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						if (selector instanceof DeferredImportSelector) {
							// EnableDiscoveryClientImportSelector、AutoConfigurationImportSelector
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate 类是一个 ImportBeanDefinitionRegistry-> 委托给它,用于注册其他 bean 定义
						// FeignClientsRegistrar、AutoConfigurationPackages、、、
						Class candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// 候选类不是ImportSelector 或 ImportBeanDefinitionRegistry-> 将其作为@Configuration类处理
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}

processImports()方法中会判断如果importCandidates导入候选类实现了ImportBeanDefinitionRegistrar接口,调用解析策略工具类实例化它的子类。并将其添加到ConfigurationClassimportBeanDefinitionRegistrars字段中(Map类型),这些方法处理完后回到processConfigurationClass()方法,将ConfigClass添加到configurationClasses集合(Map)以便执行Bean定义注册使用。

1)实例化处理

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第2张图片

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第3张图片 注意:configClass是启动类。

2)实例化

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第4张图片

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第5张图片 

 可见底层调用的是BeanUtils去处理实例化的,之前也讲解了。

3)设置并返回instance

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第6张图片

 resourceLoader为AnnotationConfigServletWebServerApplicationContext,

environment为StandServletEnvironment

4)填充集合

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第7张图片

 

4、Bean定义注册入口

this.reader.loadBeanDefinitions(configClasses);便是注册@Configuration类型的入口,也是注册ImportBeanDefinitionRegistrar类型入口,可按照之前大的逻辑不难发现会走到ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()方法,将上面解析的configurationClasses集合传递进来。

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第8张图片

 

4.1、loadBeanDefinitions()逻辑

	public void loadBeanDefinitions(Set configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			// 999520
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

遍历读取 configurationModel,根据其内容向注册中心注册 bean 定义

4.2、loadBeanDefinitionsForConfigurationClass()逻辑

	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		// 注册BeanDefinition
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			// MyBatisPlus拦截器走这里注册定义、NacosServiceAutoConfiguration、NacosDiscoveryAutoConfiguration、
			// NacosServiceRegistryAutoConfiguration ->nacosServiceRegistry、nacosRegistration、nacosAutoServiceRegistration、
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		// 如:EnableConfigurationPropertiesRegistrar
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

这里的逻辑之前走了一部分,这次会走底部的loadBeanDefinitionsFromRegistrars()逻辑,从入参就可以略知一二了。

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第9张图片

注意:configClass是启动类。 

4.3、loadBeanDefinitionsFromRegistrars()逻辑

	private void loadBeanDefinitionsFromRegistrars(Map registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry,
						this.importBeanNameGenerator));
	}

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第10张图片

 

这里遍历registrars所有登记员,然后调用具体登记员的批量登记方法,详细逻辑后面分析。

4.4、ImportBeanDefinitionRegistrar接口的registerBeanDefinitions()逻辑

	default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata,
										 BeanDefinitionRegistry registry,
										 BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}

【微服务】SpringBoot启动流程初始化OpenFeign的入口_第11张图片

 

进入到这里后,委托registerBeanDefinitions(importingClassMetadata, registry)处理。从步骤3中可见它会交由它的实现类FeignClientRegistrar去处理相应的细节,具体下一篇文章会分析。

你可能感兴趣的:(Spring家族,spring)