SpringBoot自动配置(装配)流程(springboot自动装配和自动配置)

  本篇文章为你整理了SpringBoot自动配置(装配)流程(springboot自动装配和自动配置)的详细内容,包含有springboot自动装配流程图 springboot自动装配和自动配置 springboot自动装配原理简言之 springboot自动配置的原理总结 SpringBoot自动配置(装配)流程,希望能帮助你了解 SpringBoot自动配置(装配)流程。

  ​ 首先,我们要了解在@SpringBootApplication注解的内部,还具有@EnableAutoConfiguration,@SpringBootConfiguration,@ComponentScan三个主要注解。

  

@SpringBootConfiguration //标注该类是配置类,需要通过该类查找自动配置文件

 

  @EnableAutoConfiguration //自动配置的关键注解 其内部就是执行自动配置的代码

  @ComponentScan(excludeFilters = {

   //type : 要使用的筛选器类型 , classes 指定类型筛选器

   //TypeExcludeFilter.class 筛选掉spirngBootApplication中被指定排除的配置类

   @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),

   //AutoConfigurationExcludeFilter 将配置类与spirng.factories中的EnableAutoConfiguration对应的配置类进行对比匹配, 如果一致,会被排除掉

   @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }

   ) //扫描指定包的文件,将带有特定注解的类注入到Bean中

  public @interface SpringBootApplication {

  

 

  @ComponentScan

  @ComponentScan注解主要用来扫描我们项目中的所有被像@service ,@Repository , @Controller,@configuration 等注解修饰的类, 将其注入到我们的IOC容器中,其中也包括我们的自动配置的文件:

  

@Retention(RetentionPolicy.RUNTIME)

 

  @Target(ElementType.TYPE)

  @Documented

  @Repeatable(ComponentScans.class) //表示可以重复利用@ComponentScan注解

   *作用 : 可以扫描指定的包,如果未指定包范围,将从该注解标注类所在的包进行扫描,

   * 与XML形式的<context:component scan>不同的是 @componentScan没有Config属性(true * 就开启了属性自动注入的功能,如果是false就是关闭属性自动注入的功能),因为使用

   * @ComponentScan则默认所有的类都进行自动注入,会将所有扫描到的组件注入到IOC容器中

  public @interface ComponentScan {

  

 

  @SpringBootConfiguration

  @SpringBootConfiguration 是SpringBoot替代@Configuration的注解,增加了自动找到配置的功能

  

@Target(ElementType.TYPE)

 

  @Retention(RetentionPolicy.RUNTIME)

  @Documented

  @Configuration //表示这是一个配置类 通过其间接了解到,@SpringBootApplication也是一个配置类

   * 用作Spring的标准@Configuration注解的替代,以便可以自动找到配置

  public @interface SpringBootConfiguration {

  

 

  @EnableAutoConfiguration

  @EnableAutoConfiguration注解就是启动自动配置的关键注解,其内部使用了@import注解引入了一个AutoConfigurationImportSelector 自动配置类选择器

  

@AutoConfigurationPackage //自动配置所在包注解,通过basePackages指定配置所在的包或者通过basePackageClasses指定基本包类,如果未指定,会默认注册指定注解类所在的包

 

  //AutoConfigurationImportSelector自动配置选择器,实现了ImportSelector接口,重写了selectImports方法,自动配置的具体实现就在其内部进行

  //ImportSelector接口作用 :根据给定的选择条件(通常是一个或多个注解属性)确定应导入哪个配置类。

  @Import(AutoConfigurationImportSelector.class)

  public @interface EnableAutoConfiguration {

  

 

  ​ 在其内部重写了selectImports方法, 通过调用getAutoConfigurationEntry()方法根据传入的注解元数据,获取到自动配置类的实体,而后从实体中获取具体的配置信息,配置信息在实体内部是一个list集合,所以将其转化为String数组后返回。

  

//为方便显示及理解,省略了该类实现的部分接口和具体的代码实现,需要了解可进入源码查看 

 

  public class AutoConfigurationImportSelector implements DeferredImportSelector {

   @Override

   public String[] selectImports(AnnotationMetadata annotationMetadata) {

   //AnnotationMetadata: 配置类的注解元数据,也就是配置类的注解信息

   //调用getAutoConfigurationEntry()方法根据传入的注解信息,获取并返回自动配置类的实体

   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);

   //从配置实体中获取具体的配置信息,返回的是一个list集合,而后通过toStringArray()方法转存到字符串数组中返回

   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

  

 

  getAutoConfigurationEntry()

  

//可以先看下获取的大致流程,而后进入查看器方法内部的具体实现

 

  protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {

   //1. 从注解元数据中获取注解的相应属性,将相应属性存储到map中返回

   //1.1AnnotationAttributes是一个Map集合,其继承了LinkedHashMap

   AnnotationAttributes attributes = getAttributes(annotationMetadata);

   //2. 通过getCandidateConfigurations()方法根据注解元数据和注解的属性信息 获取应该进行自动配置的类名,可以理解为自动配置候选项

   List String configurations = getCandidateConfigurations(annotationMetadata, attributes);

   //2.1 通过removeDuplicates()方法对自动配置的类名进行去重处理

   configurations = removeDuplicates(configurations);

   //3. 根据注解元数据和注解属性获取到需排除配置项

   Set String exclusions = getExclusions(annotationMetadata, attributes);

   //3.1检查是否有无效的排除类存在

   checkExcludedClasses(configurations, exclusions);

   //3.2从自动配置候选项中删除需要排除的配置项

   configurations.removeAll(exclusions);

   //4. 调用getConfigurationClassFilter()方法获取到获取配置的所有AutoConfigurationImportFilter的实现类(对spring.factories进行过滤的类),调用filter方法对配置文件进行筛选,而后返回需要自动配置的类

   configurations = getConfigurationClassFilter().filter(configurations);

   //5. 根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件,最后根据多次过滤、判重返回配置类合集

   fireAutoConfigurationImportEvents(configurations, exclusions);

   //6. 创建一个新的配置实体ConfigurationEntry并返回,包含需要配置项configurations,和被排除配置项exclusions

   return new AutoConfigurationEntry(configurations, exclusions);

  

 

  下面了解以下getAutoConfigurationEntry()内部调用的方法源码

  从注解元数据中返回相应的属性信息

  
* getAnnotationClass() 返回源注解类 -- EnableAutoConfiguration.class

   * getAnnotationClass().getName(); 获取注解类的完全限定类名

   String name = getAnnotationClass().getName();

   * metadata.getAnnotationAttributes(String annotationName,boolean classValuesAsString)

   * 作用: 检索给定注解的属性

   * @param1 要查找的注解类的完全限定类名

   * @param2 是否将类引用转换为String类名,以便作为返回Map中的值公开,而不是可能必须首先加载的类引用

   *AnnotationAttributes.fromMap(@Nullable Map String, Object map);

   * 基于给定的集合返回AnnotationAttributes实例。如果该集合是AnnotationAttributes实例或其子类,它将被强制转换并立即返回,而无需创建新实例。否则,将通过将提供的映射传递给AnnotationAttributes的map)的构造函数来创建新实例。其参数是一个Map类型的注解属性数据源,也就是attrbuties

   AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));

   *Assert类 是一个协助验证参数的断言实用程序类,详细使用可以查看其源码

   * Assert.notNull(@Nullable Object object, Supplier String messageSupplier)方法

   * 作用 : 判断对象是不是null, 如果为null,报错提示

   * param1 : 要进行判断的对象

   * param2 : 如果为null,要给予返回的异常信息

   Assert.notNull(attributes, () - "No auto-configuration attributes found. Is " + metadata.getClassName()+ " annotated with " + ClassUtils.getShortName(name) + "?");

   //返回注解元数据的属性信息map集合

   return attributes;

  

 

 

  
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes);

  

/**

 

   *根据注解元数据和注解的属性信息 获取应该进行自动配置的类名,可以理解为自动配置的候选项(初选名单)

   *param1 元注解数据

   *param2 元注解数据的属性信息集合

   *return List String 存储的数据就是应该继续宁自动配置的类名

  protected List String getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

   //SpringFactoriesLoader是一个用于框架内部使用的通用工厂加载机制

   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;

  

 

  


//通过removeDuplicates()方法对自动配置的类名进行去重处理

 

  //利用Set集合数据不重复特性,将list集合存储到LinkedHashSet集合中进行去重处理,而后再将去重的结果存储到List集合中返回

  protected final T List T removeDuplicates(List T list) {

   return new ArrayList (new LinkedHashSet (list));

  

 

  从自动配置项中筛选被排除配置项

  configurations.removeAll(exclusions);

  

//从自动配置候选项中筛选需排除配置项

 

  protected Set String getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {

   //创建一个需排除配置项集合excluded

   Set String excluded = new LinkedHashSet ();

   //从属性信息集合中获取到key为exclude的值,将其存储到excluded集合中

   excluded.addAll(asList(attributes, "exclude"));

   //从属性信息集合中获取到key为excludeName的数据,返回的是一个字符串数组,返回后将其转化为List集合,存储到excluded集合中

   excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));

   * getExcludeAutoConfigurationsProperty():

   *返回 spring.autoconfigure.exclude 属性排除的自动配置

   excluded.addAll(getExcludeAutoConfigurationsProperty());

   return excluded;

  -----------------------------------------------------------------------------------------

  /*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/

  -----------------------------------------------------------------------------------------

  //attributes.getStringArray("excludeName")

  public String[] getStringArray(String attributeName) {

   return getRequiredAttribute(attributeName, String[].class);

  

 

  exclude 和excludeName 都是指定某些类在项目启动时不进行自动配置,其一般在@SpringBootApplication 中进行配置。

  检查是否有无效的排除类存在

  1 configurations.removeAll(exclusions);

  

//检查是否有无效的排除类存在

 

  private void checkExcludedClasses(List String configurations, Set String exclusions) {

   //创建一个用于存储无效配置项的集合

   List String invalidExcludes = new ArrayList (exclusions.size());

   //循环需排除配置项

   for (String exclusion : exclusions) {

   //根据类的全限定名判断该类是否存在且可以被加载,并且 需排除配置项集合是否包含该类

   if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) !configurations.contains(exclusion)) {

   //如果存在,且不再需排除配置项的集合中,将其添加到无效配置项集合中

   invalidExcludes.add(exclusion);

   //如果无效配置项集合不为空,说明存在无效配置项

   if (!invalidExcludes.isEmpty()) {

   //处理无效配置项 -- 报错 IllegalStateException 无效状态异常

   handleInvalidExcludes(invalidExcludes);

  -----------------------------------------------------------------------------------------

  /*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/

  -----------------------------------------------------------------------------------------

   *ClassUtils.isPresent() 根据类名称判断是否存在并且可以加载,如果类或其依赖项之一不存在或无法 加载返回false

   * param1 className 要检查的类的名称

   * param2 classLoader 要使用的类加载器(如果为null,表示默认的类加载器)

  public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {

   try {

   //forName(类名称,类加载器) 用于替换Class.forName()方法, 并且还返回所提供名称的类实例

   forName(className, classLoader);

   return true;

   catch (IllegalAccessError err) {

   throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +

   className + "]: " + err.getMessage(), err);

   catch (Throwable ex) {

   // Typically ClassNotFoundException or NoClassDefFoundError...

   return false;

  

 

  从自动配置项中删除需要被排除的配置项

  2 configurations.removeAll(exclusions);

  

/**

 

   *从自动配置候选项中删除需要排除的配置项

   * 集合A.removeAll(集合B);作用就是从集合A数据项中删除掉集合B所包含的元素

  configurations.removeAll(exclusions);

  

 

  创建配置类过滤器对配置项进行筛选过滤

  configurations = getConfigurationClassFilter().filter(configurations);

  

//通过getConfigurationClassFilter()获取所有AutoConfigurationImportFilter的实现类(对spring.factories进行过滤的类),而后调用filter方法对配置文件进行筛选,而后返回需要自动配置的类

 

  configurations = getConfigurationClassFilter().filter(configurations);

  -----------------------------------------------------------------------------------------

  /*下面方法是上面方法所调用的个别方法源码,不深究者可以略过*/

  -----------------------------------------------------------------------------------------

  //获取配置类过滤器

  private ConfigurationClassFilter getConfigurationClassFilter() {

   //this.configurationClassFilter当前类的配置类过滤器是不是为null

   if (this.configurationClassFilter == null) {

   // 获取AutoConfigurationImportFilter过滤器的实现类集合

   List AutoConfigurationImportFilter filters = getAutoConfigurationImportFilters();

   for (AutoConfigurationImportFilter filter : filters) {

   invokeAwareMethods(filter); //在监听器注入是有描述,两者使用的同一方法

   //实例化配置类过滤器 ,根据 类加载器和过滤器实现类实例化配置类过滤器

   //ConfigurationClassFilter类内部含有类加载器和过滤器实现类集合的属性

   this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);

   //返回配置类过滤器

   return this.configurationClassFilter;

  //getAutoConfigurationImportFilters(); 获取AutoConfigurationImportFilter过滤器的实现类集合

  protected List AutoConfigurationImportFilter getAutoConfigurationImportFilters() {

   * List T loadFacotries(Class T factoryType, @Nullable ClassLoader classLoader)

   * 使用给定的类加载器从{"META-INF/spring.factories"}加载并实例化指定过滤器工厂的实现类

   * 在结果返回之前会对结果集进行排序

   * param1 表示工厂的接口或者抽象类,-- 生成其子类

   * param2 当前类的类加载器-- 用于加载抽象类的实现类

   * return 返回指定接口或者抽象类的实现类List集合

   //返回AutoConfigurationImportFilter实现类的集合

   return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);

  //configurations = getConfigurationClassFilter().filter(configurations);

  //过滤 自动配置项

  List String filter(List String configurations) {

   long startTime = System.nanoTime();

   //将将配置转化为字符串数组

   String[] candidates = StringUtils.toStringArray(configurations);

   boolean skipped = false;

   for (AutoConfigurationImportFilter filter : this.filters) {

   //循环过滤条件与配置项进行一一匹配,剔除掉条件不成立的配置项

   boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);

   for (int i = 0; i match.length; i++) {

   if (!match[i]) {

   candidates[i] = null;

   skipped = true;

   //如果全都符合则直接返回配置项集合

   if (!skipped) {

   return configurations;

   //创建结果集集合

   List String result = new ArrayList (candidates.length);

   for (String candidate : candidates) {

   //配置项不为null就添加到配置类中

   if (candidate != null) {

   result.add(candidate);

   //返回结果

   return result;

  

 

  创建配置类监听器对自动配置进行监听

  fireAutoConfigurationImportEvents(configurations, exclusions);

  

//根据spring.factories文件中的AutoConfigurationImportListener事件监听器发布并处理监听事件,最后根据多次过滤、判重返回配置类合集

 

  private void fireAutoConfigurationImportEvents(List String configurations, Set String exclusions) {

   //从{ "META-INF/spring.factories"}加载并实例化自动配置类监听器 AutoConfigurationImportListener的实现类集合

   List AutoConfigurationImportListener listeners = getAutoConfigurationImportListeners();

   //如果监听器不为空的话

   if (!listeners.isEmpty())

   //创建fireAutoConfigurationImportEvents监听事件

   AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);

   //循环遍历 判断listener是否是 Aware 通过Aware接口 实现对bean各阶段的监听

   for (AutoConfigurationImportListener listener : listeners) {

   //通过Aware类的实现类对监听器进行配置 -- 解这一模块,可以重点关注以下Aware接口

   invokeAwareMethods(listener);

   //进行自动配置的导入 event 到自动配置时进行的事件-- 对自动配置的监听

   listener.onAutoConfigurationImportEvent(event);

  //根据Aware类对bean的各阶段进行监听配置

  private void invokeAwareMethods(Object instance) {

   //判断监听器是否是Aware或其实现类

   if (instance instanceof Aware) {

   if (instance instanceof BeanClassLoaderAware) {

   * BeanClassLoaderAware 允许bean知道bean的回调ClassLoader,即当前bean工厂用来加载bean类的类加载器。这主要是由框架类来实现的,这些框架类必须通过名称来获取应用程序类,尽管它们本身可能

  从共享类加载器加载的。

   * 方法 setBeanClassLoader(ClassLoader classLoader);

   * 将bean的类加载器 提供给bean实例的回调。

   * 作用范围: 在填充普通bean属性之后,初始化回调之前调用

   ((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);

   if (instance instanceof BeanFactoryAware) {

   * BeanFactoryAware 表示接口知道其拥有的{BeanFactory}的bean实现。

   *注意 :大多数的bean都可以通过属性注入和构造注入接收对bean的引用

   *方法 :setBeanFactory(BeanFactory beanFactory)

   * 向bean实例提供拥有工厂的回调。

   * 作用范围: 在填充普通bean属性之后,初始化回调之前调用,

   ((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);

   if (instance instanceof EnvironmentAware) {

   * EnvironmentAware 表示该接口可以收到其运行环境的通知

   *方法 :setEnvironment(Environment environment);

   * 设置此组件的运行环境

   ((EnvironmentAware) instance).setEnvironment(this.environment);

   if (instance instanceof ResourceLoaderAware) {

   * ResourceLoaderAware 接口,该接口可以收到该对象运行的ResourceLoader资源封装类加载器

   *方法 :setResourceLoader(ResourceLoader resourceLoader);

   *作用 :设置此对象运行的ResourceLoader。可能是一个ResourcePatternResolver

   *作用范围: 在填充普通bean属性之后,初始化回调之前调用

   ((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);

  

 

  创建新的配置实体后返回SelectImports方法体内

  return new AutoConfigurationEntry(configurations, exclusions);

  

根据需要配置项和被排除项实例化新的配置实体,并返回

 

  AutoConfigurationEntry(Collection String configurations, Collection String exclusions) {

   this.configurations = new ArrayList (configurations);

   this.exclusions = new HashSet (exclusions);

  

 

  将配置实体中的配置信息转化为字符串数组返回,完成注入

  

//获取最终要导入的配置实体

 

  AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);

  //从配置实体中获取具体的配置信息,返回的是一个list集合,而后通过toStringArray()方法转存到字符串数组中返回

   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

  

 

  本笔记个人查看源码时根据立即理解缩写,如有错误可留言告知,谢谢

  以上就是SpringBoot自动配置(装配)流程(springboot自动装配和自动配置)的详细内容,想要了解更多 SpringBoot自动配置(装配)流程的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: