springboot 监听所有异常_SpringBoot自动配置原理源码解读

SpringBoot自动配置原理源码解读

1.@SpringBootApplication:通过这个注解,不仅仅标记这是一个SpringBoot应用,而且还开启自动配置的功能

3b8a68e63876368fcde391fea7a84540.png

主要注解EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage  //主要功能自动配置包,他会获取主程序类所在包路径,并将包路径下的所有组件注册到Spring IOC 容器中
@Import(AutoConfigurationImportSelector.class)  //AutoConfigurationImportSelector ,导入自动配置相关的资源
public @interface EnableAutoConfiguration {

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   Class<?>[] exclude() default {};

   String[] excludeName() default {};

}

1.程序启动入口

SpringApplication.run(MVCApplication.class, args)

启动之后,无论是

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

还是

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   //最终都会调用SpringApplication(primarySources).run(args)
        return new SpringApplication(primarySources).run(args);
    }

都会从SpringApplication(primarySources).run(args)进入。

public ConfigurableApplicationContext run(String... args) {

        //创建StopWatch对象,并启动,StopWatch主要用于简单统计run启动进程的时长
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // <2> 配置 headless 属性    这个和AWT有关,可以不看
        configureHeadlessProperty();
        // 获得 SpringApplicationRunListener 的数组,并启动监听
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            // <3> 创建  ApplicationArguments 对象
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // <4> 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            // <5> 打印 Spring Banner
            Banner printedBanner = printBanner(environment);
            // <6> 创建 Spring 容器。
            context = createApplicationContext();
            // <7> 异常报告器
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            // <8> 主要是调用所有初始化类的 initialize 方法
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // <9> 初始化 Spring 容器。
            refreshContext(context);
            // <10> 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
            afterRefresh(context, applicationArguments);
            // <11> 停止 StopWatch 统计时长
            stopWatch.stop();
            // <12> 打印 Spring Boot 启动的时长日志。
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            // <13> 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
            listeners.started(context);
            // <14> 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            // <14.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        // <15> 通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            // <15.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

自动配置从 <9> 初始化 Spring 容器。refreshContext(context)进入。

private void refreshContext(ConfigurableApplicationContext context) {
   // <1> 开启(刷新)Spring 容器
   refresh(context);
   // <2> 注册 ShutdownHook 钩子
   if (this.registerShutdownHook) {
      try {
         context.registerShutdownHook();
      }
      catch (AccessControlException ex) {
         // Not allowed in some environments.
      }
   }
}

开启Spring容器 refresh(context),进入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()));
   //<1>获得autoconfigurationEntry对象
   AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
         .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
   //<2>添加到这个list中
   this.autoConfigurationEntries.add(autoConfigurationEntry);
   // <3> 添加到 entries 中
   for (String importClassName : autoConfigurationEntry.getConfigurations()) {
      this.entries.putIfAbsent(importClassName, annotationMetadata);
   }
}

从<1>处获得获得autoconfigurationEntry对象,调用getAutoConfigurationEntry进入方法。

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
   // <1> 判断是否开启。如未开启,返回空数组。
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   // <2> 获得注解的属性
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   // <3> 获得符合条件的配置类的数组
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   // <3.1> 移除重复的配置类
   configurations = removeDuplicates(configurations);
   // <4> 获得需要排除的配置类
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   // <4.1> 校验排除的配置类是否合法
   checkExcludedClasses(configurations, exclusions);
   // <4.2> 从 configurations 中,移除需要排除的配置类
   configurations.removeAll(exclusions);
   // <5> 根据条件(Condition),过滤掉不符合条件的配置类
   configurations = filter(configurations, autoConfigurationMetadata);
   // <6> 触发自动配置类引入完成的事件
   fireAutoConfigurationImportEvents(configurations, exclusions);
   // <7> 创建 AutoConfigurationEntry 对象
   return new AutoConfigurationEntry(configurations, exclusions);
}

<1>isEnabled首先判断是否开启自动配置

protected boolean isEnabled(AnnotationMetadata metadata) {
   // 判断 "spring.boot.enableautoconfiguration" 配置判断,是否开启自动配置。
   // 默认情况下(未配置),开启自动配置。
   if (getClass() == AutoConfigurationImportSelector.class) {
      return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
   }
   return true;
}

<2>getAttributes获得注解的属性

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
   //此处 getAnnotationClass().getName() 返回的是 @EnableAutoConfiguration 注解,
   // 所以这里返回的注解属性,只能是 exclude 和 excludeName 这两个。
   String name = getAnnotationClass().getName();
   // 获得注解的属性
   AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
   Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
         + " annotated with " + ClassUtils.getShortName(name) + "?");
   return attributes;
}

此处 getAnnotationClass().getName() 返回的是 @EnableAutoConfiguration 注解,所以这里返回的注解属性,只能是 excludeexcludeName 这两个。

<3>getCandidateConfigurations获得符合条件的配置类的数组,通过loadFactoryNames拿到所有名为META-INF/spring.factories的配置文件,然后按照factoryClass的名称取到对应的值

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   //<1>加载指定类型EnableAutoConfigurations对应的,在META-INF/spring.factories 里类名的数组
   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;
}

<3.1>removeDuplicates移除重复的配置类,直接使用LinkedHashSet去重

protected final <T> List<T> removeDuplicates(List<T> list) {
   return new ArrayList<>(new LinkedHashSet<>(list));
}

<4>getExclusions获得需要排除的配置类

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   Set<String> excluded = new LinkedHashSet<>();
   // 注解上的 exclude 属性
   excluded.addAll(asList(attributes, "exclude"));
   // 注解上的 excludeName 属性
   excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
   // 配置文件的 spring.autoconfigure.exclude 属性
   excluded.addAll(getExcludeAutoConfigurationsProperty());
   return excluded;
}

主要就是![image-20200403195153713](/Users/zhaoyu/Library/Application Support/typora-user-images/image-20200403195153713.png)

![image-20200403195218472](/Users/zhaoyu/Library/Application Support/typora-user-images/image-20200403195218472.png)

找到注解上的和配置文件中的这个属性

<4.1>checkExcludedClasses检验排除的配置类是否合法

<4.2>configurations.removeAll(exclusions)移除需要排除的配置类

<5>filter(configurations, autoConfigurationMetadata)根据条件过滤掉不符合条件的配置类

<6>fireAutoConfigurationImportEvents(configurations, exclusions)触发自动配置类引入完成的事件

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
   // <1> 加载指定类型 AutoConfigurationImportListener 对应的,在 `META-INF/spring.factories` 里的类名的数组。
   List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
   if (!listeners.isEmpty()) {
      // <2> 创建 AutoConfigurationImportEvent 事件
      AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
      // <3> 遍历 AutoConfigurationImportListener 监听器们,逐个通知
      for (AutoConfigurationImportListener listener : listeners) {
         // <3.1> 设置 AutoConfigurationImportListener 的属性
         invokeAwareMethods(listener);
         // <3.2> 通知
         listener.onAutoConfigurationImportEvent(event);
      }
   }
}

process方法完成之后调用getImports()方法

public Iterable<Entry> getImports() {
        Iterator var1 = this.deferredImports.iterator();

        while(var1.hasNext()) {
            ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
            this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
        }

        return this.group.selectImports();
    }
}

关键是调用selectImports方法用于筛选需要引入的类名,获得要引入的配置类

public Iterable<Entry> selectImports() {
   // <1> 如果为空,则返回空数组
   if (this.autoConfigurationEntries.isEmpty()) {
      return Collections.emptyList();
   }
   // <2.1> 获得 allExclusions
   Set<String> allExclusions = this.autoConfigurationEntries.stream()
         .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
   // <2.2> 获得 processedConfigurations
   Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
         .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
         .collect(Collectors.toCollection(LinkedHashSet::new));
   // <2.3> 从 processedConfigurations 中,移除排除的
   processedConfigurations.removeAll(allExclusions);

   // <3> 处理,返回结果
   return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
         .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
         .collect(Collectors.toList());
}

之后进入register,注册一个用于存储包名(package)的 Bean 到 Spring IoC 容器中

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
   // <1> 如果已经存在该 BEAN ,则修改其包(package)属性
   if (registry.containsBeanDefinition(BEAN)) {
      BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
      ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
      constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
   }
   // <2> 如果不存在该 BEAN ,则创建一个 Bean ,并进行注册
   else {
      GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
      beanDefinition.setBeanClass(BasePackages.class);
      beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
      beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      registry.registerBeanDefinition(BEAN, beanDefinition);
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值