• SpringBoot 自动装配原理


    什么是自动装配

    • springboot 定义一套接口规范,这套规范规定:springboot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 spring 容器,并执行类中定义的各种操作
    • 对于外部 jar 来说,只需要按照 springboot 定义的标准,就能将自己的功能装置进 springboot

    自动装配的作用

    • 自动装配能够很大程度减少开发人员对 bean 的装配工作,只需要通过把对应的 bean 对象配置到对应工程下 META-INF/spring.factories,就能够装配到 spring 容器中

    DeferredImportSelector 接口分析

    • springboot 的 AutoConfigurationImportSelector 类实现 DeferredImportSelector 接口,并且实现内部接口 Group,重写 Group 的 process() 和 selectImports() 方法
    • DeferredImportSelector 接口的 process() 和 selectImports() 方法,在 spring 调用bean定义注册后置处理器的时候会调用这个两个方法
    • process() 方法会获取 spring.factories 中用户定义的 bean 列表,selectImports() 方法获取将 process() 方法获取的 bean 对象列表包装成 Group 接口的内部类 Entry 对象
    • 在获取到 Entry 对象列表之后,将这些 bean 对象注册到容器中
    • 之后 spring 会对容器中的 bean 对象列表进行实例化和属性填充
    /**
     * 继承 ImportSelector 接口
     */
    public interface DeferredImportSelector extends ImportSelector {
    
    	/**
    	 * 返回 Group 接口实现类的 class
    	 */
    	@Nullable
    	default Class<? extends Group> getImportGroup() {
    		return null;
    	}
    
    
    	/**
    	 * Group 接口,使用必须实现这个类
    	 */
    	interface Group {
    
    		/**
    		 * 上面分组完成后 spring 会调用该方法,循环 List 里的 DeferredImportSelector 类,并循环调用 process()
    		 */
    		void process(AnnotationMetadata metadata, DeferredImportSelector selector);
    
    		/**
    		 * 每个 Group 只执行一次,返回一个迭代器,spring 会使用迭代器的 forEach 方法进行迭代,想要导入 spring 容器的类要封装成 Entry 对象
    		 */
    		Iterable<Entry> selectImports();
    
    
    		/**
    		 * Entry 实体类,持有注解和需要导入的类名称
    		 */
    		class Entry {
    
    			private final AnnotationMetadata metadata;
    
    			private final String importClassName;
    
    			public Entry(AnnotationMetadata metadata, String importClassName) {
    				this.metadata = metadata;
    				this.importClassName = importClassName;
    			}
    
    			public AnnotationMetadata getMetadata() {
    				return this.metadata;
    			}
    
    			public String getImportClassName() {
    				return this.importClassName;
    			}
    
    			@Override
    			public boolean equals(@Nullable Object other) {
    				if (this == other) {
    					return true;
    				}
    				if (other == null || getClass() != other.getClass()) {
    					return false;
    				}
    				Entry entry = (Entry) other;
    				return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));
    			}
    
    			@Override
    			public int hashCode() {
    				return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());
    			}
    
    			@Override
    			public String toString() {
    				return this.importClassName;
    			}
    		}
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    自动装配实现原理

    AutoConfigurationGroup 实现类分析

    • spring 在容器刷新的时候会调用这两个方法
    • 调用两个方法之后,用户定义的 bean 对象会被注入到 spring 容器中,之后会统一对bean对象进行实例化和属性填充
    // 解析用户定义在 spring.factories 中的 bean 对象
    @Override
    public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    	// 确定是 AutoConfigurationImportSelector 子类
    	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
    			() -> String.format("Only %s implementations are supported, got %s",
    					AutoConfigurationImportSelector.class.getSimpleName(),
    					deferredImportSelector.getClass().getName()));
    	// 从 "META-INF/spring.factories" 文件获取需要的自动配置类
    	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
    			.getAutoConfigurationEntry(annotationMetadata);
    	// 将需要的类传入全局变量,以便 selectImports 方法使用
    	this.autoConfigurationEntries.add(autoConfigurationEntry);
    	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
    		this.entries.putIfAbsent(importClassName, annotationMetadata);
    	}
    }
    
    // 将获取出来的bean对象排序、过滤包装成 DeferredImportSelector.Group.Entry 对象
    @Override
    public Iterable<Entry> selectImports() {
    
    	// 没有需要自动装配的类,返回空集合
    	if (this.autoConfigurationEntries.isEmpty()) {
    		return Collections.emptyList();
    	}
    
    	// 去除不需要的
    	Set<String> allExclusions = this.autoConfigurationEntries.stream()
    			.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
    	Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
    			.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
    			.collect(Collectors.toCollection(LinkedHashSet::new));
    	processedConfigurations.removeAll(allExclusions);
    
    	// 排序,封装对象并返回集合
    	return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
    			.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
    			.collect(Collectors.toList());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    • 获取 spring.factories 中的 bean 对象列表
    // 获取 spring.factories 中的 bean 对象
    protected AutoConfigurationEntry  getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return EMPTY_ENTRY;
    		}
    		// 获取注解的属性的内容
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    		// 获取候选 bean,获取 spring.factories 中定义的bean
    		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    		// 去重
    		configurations = removeDuplicates(configurations);						
    		// 去除排除的类					
    		Set<String> exclusions = getExclusions(annotationMetadata, attributes);			
    		checkExcludedClasses(configurations, exclusions);
    		configurations.removeAll(exclusions);
    		configurations = getConfigurationClassFilter().filter(configurations);
    		fireAutoConfigurationImportEvents(configurations, exclusions);
    		return new AutoConfigurationEntry(configurations, exclusions);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    流程总结

    • springboot 自动装配的流程
    • spring 容器刷新对 DeferredImportSelector 的处理
  • 相关阅读:
    springboot中药知识分享网站设计毕业设计源码201818
    思科模拟器
    vue3+ts实现幻灯片效果
    前端开发面试题—JavaScript原型链
    线程池详解
    MyBatis - 两种查询树形数据(最多三级结构)
    Vue学习笔记 —— 使用Vue的ref实现动态添加活动类名
    基于OpenCV的图形分析辨认05
    Rowset 的元数据一直存储在内存中
    C++演变历史
  • 原文地址:https://blog.csdn.net/qq_41956014/article/details/127755479