Spring Source Code Analysis Supplement One: Processing of DeferredImportSelector

I. Introduction

This series is a supplement to some missing content in the process of reviewing the source code analysis. The content is only used for personal learning records.


In Spring Source Code Analysis Derivative Part Seven: ConfigurationClassPostProcessor Part I , we talked about the completion of the analysis of ImportSelector and DeferredImportSelector in ConfigurationClassPostProcessor.
The call to ImportSelector is to directly call the ImportSelector#selectImports method to complete the analysis, but the call to DeferredImportSelector is not so straightforward. This article analyzes the calling process of DeferredImportSelector.

二、 DeferredImportSelector

DeferredImportSelectorIt is a ImportSelectorsub-interface interface.

DeferredImportSelector There are two characteristics:

  • ImportSelector that inherits this interface will run after all @Configuration configuration classes are processed. This is because ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)until parsing out the other candidates will be called class configuration method this.deferredImportSelectorHandler.process();to resolveDeferredImportSelector
  • If more than one DeferredImportSelector is defined, the Order interface is used for sorting. This is also in this.deferredImportSelectorHandler.process();sorted call.

By Sike source series [resolve] the principle ImportSelector Interface words:

The DeferredImportSelector interface is a sub-interface of the ImportSelector interface. This interface will run after all @Configuration configuration classes (not including the automated configuration classes, which are the configuration classes in the spring.factories file) are processed; when the selector and @Conditional conditional annotations are together It is particularly useful when used. This interface can also be used with the interface Ordered or @Ordered to define the priority of multiple selectors

Three, source code analysis

1. Preprocessing of DeferredImportSelector

Because DeferredImportSelector has post-processing features, it cannot be processed immediately when the DeferredImportSelector is scanned at the beginning. It needs to be saved and processed in a unified manner at the end.
The processing of DeferredImportSelector in ConfigurationClassParser#processImports is as follows:

// deferredImportSelectorHandler  为 org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler
	// 这一步实际上是将 configClass 和 selector 保存到了一个集合(deferredImportSelectors)中,集合(deferredImportSelectors)标记着待处理的selector
	this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);

The specific implementation is as follows:

	// ConfigurationClassParser.DeferredImportSelectorHandler#handle
	// deferredImportSelectors  保存待处理的 Selector  
	private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
	// configClass 是持有该@Import 注解的 配置类, importSelector 是引入的 DeferredImportSelector 
	public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
    
    
			// 将 DeferredImportSelector  和其引入的配置类保存起来。
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			// 如果deferredImportSelectors 为空,则重新注册
			if (this.deferredImportSelectors == null) {
    
    
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				handler.register(holder);
				handler.processGroupImports();
			}
			else {
    
    
				// 将当前的 config 和 Selector 的持有者保存起来
				this.deferredImportSelectors.add(holder);
			}
		}

2. The real processing of DeferredImportSelector

In ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)the last sentence dealt DeferredImportSelector

	this.deferredImportSelectorHandler.process();

The detailed implementation is as follows:

	public void process() {
    
    
		// 获取待处理的 DeferredImportSelectorHolder
		List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
		this.deferredImportSelectors = null;
		try {
    
    
			if (deferredImports != null) {
    
    
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				// 排序
				deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
				// 1. 根据不同的group 进行分组注册
				deferredImports.forEach(handler::register);
				// 2. 按照分组调用
				handler.processGroupImports();
			}
		}
		finally {
    
    
			this.deferredImportSelectors = new ArrayList<>();
		}
	}

2.1 handler::register

There are two steps here:

  1. Divide different DeferredImportSelectorHolder into groups
  2. Save the information of DeferredImportSelectorHolder to configurationClasses. (Get when calling later)
	public void register(DeferredImportSelectorHolder deferredImport) {
    
    
		// 获取当前 DeferredImportSelector  的Group
		Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
		DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
				(group != null ? group : deferredImport),
				key -> new DeferredImportSelectorGrouping(createGroup(group)));
		// 将当前 DeferredImportSelector  添加到同一分组中的
		grouping.add(deferredImport);
		// 保存需要处理的配置类
		this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getConfigurationClass());
	}

2.2 handler.processGroupImports()

In this step, the classes introduced by DeferredImportSelector in the group are packaged by entry.getImportClassName() according to different groups, and then the processImports method is called for a new round of analysis.

	public void processGroupImports() {
    
    
		// 遍历每个分组
		for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
    
    
			// 获取分组的过滤器
			Predicate<String> exclusionFilter = grouping.getCandidateFilter();
			// 遍历分组中所有的 Entry (封装了需要引入的类的信息)
			grouping.getImports().forEach(entry -> {
    
    
				// 从 configurationClasses 集合中获取到对应的 ConfigurationClass 。其中保存
				ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
				try {
    
    
					// 对 configurationClass 进行解析。这里的解析在 ConfigurationClassPostProcessor  文章已经有过解释。
					// entry.getImportClassName() 获取到了引入的类
					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);
				}
			});
		}
	}

Which grouping.getImports()is to achieve the following

	// org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports
	public Iterable<Group.Entry> getImports() {
    
    
		for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
    
    
			// 调用 DeferredImportSelector.Group#process
			this.group.process(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getImportSelector());
		}
		// 调用 DeferredImportSelector.Group#selectImports
		return this.group.selectImports();
	}

What we call here is DefaultDeferredImportSelectorGroup

	private static class DefaultDeferredImportSelectorGroup implements Group {
    
    

		private final List<Entry> imports = new ArrayList<>();

		@Override
		public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
    
    
			// 调用了ImportSelector#selectImports 方法
			for (String importClassName : selector.selectImports(metadata)) {
    
    
				this.imports.add(new Entry(metadata, importClassName));
			}
		}

		@Override
		public Iterable<Entry> selectImports() {
    
    
			// 直接将 Imports 返回
			return this.imports;
		}
	}


In summary, it can be seen that the processing of DeferredImportSelector is not to directly call the ImportSelector#selectImports method. Instead, it calls the DeferredImportSelector.Group#process and Group#selectImports methods to complete the import function.


Above: For the content, please refer to
https://mingyang.blog.csdn.net/article/details/108861935.
If there is any intrusion, please contact and delete it. The content is only used for self-record learning. If there is any error, please correct me

Guess you like

Origin blog.csdn.net/qq_36882793/article/details/114300705
Recommended