springboot 监听所有异常_Spring Boot源码解析——Spring Boot系列

8e9221e0de0163975806e60f213ebac5.png

一、自动装配原理

496dd554de6ddfcf6074c30ee2968029.png

  之前博文已经讲过,@SpringBootApplication继承了@EnableAutoConfiguration,该注解导入了AutoConfigurationImport Selector,这个类主要是扫描spring-boot-autoconfigure下面的META-INFspring.factories中的EnableAutoConfiguration对应的全类名,其中XXXAutoConfiguration都是一个个自动配置类。

3c79f2fbd675d39d26fe2d1dee41bf73.png

  自动装配原理具体参考:Spring Boot系列(二):Spring Boot自动装配原理解析

二、Spring Boot的jar启动

  1、Spring Boot自动装配Tomcat组件

  ① EmbeddedWebServerFactoryCustomizerAutoConfiguration内嵌的Web容器工厂定制器自动装配类,装配了TomcatWebServerFactoryCustomizer组件

fd928c8a49d548e2ec05b63986866082.png

  Tomcat工厂定制器TomcatWebServerFactoryCustomizer用来设置容器的属性,把ServerProperties中的属性设置到Tomcat容器的工厂中。

f325cc42ebd1af68a95a3a64d47436bb.png

  ServerProperties服务的属性类:

f4a950866aae06ede6baaa08d71f18ab.png

  ② ServletWebServerFactoryAutoConfiguration,ServletWeb工厂自动装配类,装配了如下四个组件

  • ServletWebServerFactoryCustomizer:用来定制ServletWeb服务工厂
  • TomcatServletWebServerFactoryCustomizer:用来定制TomcatServletWeb服务工厂
  • ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar :后置处理器
  • ServletWebServerFactoryConfiguration:用来配置TomcatServletWeb服务工厂
ed8febf227dbf352e1223b9268e9f45f.png

  2、SpringApplication.run启动流程

  ① new SpringApplication(primarySources),创建了一个SpringApplication

104e5125d145ad62c5d037a8acfbff5c.gif
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {        this.resourceLoader = resourceLoader;        Assert.notNull(primarySources, "PrimarySources must not be null");        //设置主配置类 我们自己写的Spring Boot的启动类        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));        //设置web应用的类型        this.webApplicationType = WebApplicationType.deduceFromClasspath();        //设置容器初始化器(ApplicationContextInitializer类型的)        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));        //把监听器设置到SpringApplication中[ApplicationListener]        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));        //设置主配置类        this.mainApplicationClass = deduceMainApplicationClass();    }
104e5125d145ad62c5d037a8acfbff5c.gif

  ② SpringApplication的run方法:

  主要流程:

  第一:创建容器对象

  第二:去META-INFO/spring.factories中获取SpringApplicationRunListener监听器(事件发布监听器)

  第三:发布容器starting事件(通过spring的事件多播器)

  第四:封装命令行参数

  第五:准备容器环境

  第六:打印Springboot的图标

  第七:根据webApplicationType来创建容器

  第八:准备容器上下文

  第九:发布容器启动事件

  第十:发布容器运行事件

104e5125d145ad62c5d037a8acfbff5c.gif
public ConfigurableApplicationContext run(String... args) {        StopWatch stopWatch = new StopWatch();        stopWatch.start();        //容器对象        ConfigurableApplicationContext context = null;        Collection exceptionReporters = new ArrayList<>();        configureHeadlessProperty();        //去META-INFO/spring.factories中获取SpringApplicationRunListener监听器(事件发布监听器)        SpringApplicationRunListeners listeners = getRunListeners(args);        //发布容器starting事件(通过spring的事件多播器)        listeners.starting();        try {            //封装命令行参数            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);            /**             * 准备容器环境             * 1: 获取或者创建环境             * 2:把命令行参数设置到环境中             * 3:通过监听器发布环境准备事件             */            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);            configureIgnoreBeanInfo(environment);            //打印Springboot的图标            Banner printedBanner = printBanner(environment);            //创建容器根据webApplicationType来创建容器(通过反射创建)            context = createApplicationContext();            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,                    new Class[] { ConfigurableApplicationContext.class }, context);            /**             * 准备上下文             * 1:把环境设置到容器中             * 2: 循环调用ApplicationContextInitializer进行容器初始化工作             * 3: 发布容器上下文准备完成事件             * 4: 注册关于Springboot特性的相关单例Bean             * 5: 发布容器上下文加载完毕事件             */            prepareContext(context, environment, listeners, applicationArguments, printedBanner);            refreshContext(context);            //运行ApplicationRunner和CommandLineRunner            afterRefresh(context, applicationArguments);            stopWatch.stop();            if (this.logStartupInfo) {                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);            }            //发布容器启动事件            listeners.started(context);            //运行ApplicationRunner和CommandLineRunner            callRunners(context, applicationArguments);        }        catch (Throwable ex) {            //出现异常调用异常分析保护类进行分析            handleRunFailure(context, ex, exceptionReporters, listeners);            throw new IllegalStateException(ex);        }        try {            //发布容器运行事件            listeners.running(context);        }        catch (Throwable ex) {            handleRunFailure(context, ex, exceptionReporters, null);            throw new IllegalStateException(ex);        }        return context;    }
104e5125d145ad62c5d037a8acfbff5c.gif

  ③ org.springframework.boot.SpringApplication#refreshContext

  ④ org.springframework.boot.SpringApplication#refresh

  ⑤ org.springframework.context.support.AbstractApplicationContext#refresh

  到了AbstractApplicationContext#refresh方法,之前讲过Spring IoC源码解析讲过该方法的12大步,这里就不细说,详细可以参考:Spring系列(三):Spring IoC源码解析,里面说过有一步就是onRefresh(),这个方法默认是空的,由子类根据自身需要去实现

  ⑥ org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

  该onRefresh方法分2步

  第一:super.onRefresh(); 调用父类的onRefresh()

  第二:createWebServer();创建Web服务,很重要,很重要,很重要!!!

  ⑦ createWebServer()方法

  第一:ServletContext servletContext = getServletContext(); 获取Servlet的上下文

  第二:ServletWebServerFactory factory = getWebServerFactory();获取Tomcat的Web服务工厂

  第三:this.webServer = factory.getWebServer(getSelfInitializer()); 创建一个Web服务器

22fca68418e488d59bc4fc8b01dcdd5d.png

  ⑧ TomcatServletWebServerFactory#getWebServer()方法,主要用于创建一个Tomcat Web容器

b50ee11a1972945095c5357f1284ea77.png

  到此我们知道Spring Boot的启动通过Spring IoC的refresh中的的onRefresh()带动了Tomcat的启动,跟我们之前我们学Spring Mvc的时候刚好相反,Spring Mvc的是Tomcat的启动带动了Spring容器的启动;

三、普通Web工程启动

  1、普通的web工程,我们找到web.xml,会发现都配置了如下的加载Spring的配置。

b368343aa6674578252285990d7639b4.png

  2、Tomcat启动的时候会调用该上下文加载的的监听器的contextInitialized方法,我们进入到该方法:

91b3e143557c98f9e86074684e613646.png

  3、进入初始化Web应用上下文initWebApplicationContext方法中:

  • this.context = createWebApplicationContext(servletContext);
  • configureAndRefreshWebApplicationContext(cwac, servletContext);

  4、进去到configureAndRefreshWebApplicationContext(cwac, servletContext)方法中:

f94f54922370998e7bf3e72404356aea.png

  5、进入到refresh方法实际就到了org.springframework.context.support.AbstractApplicationContext#refresh的方法

  这个方法很熟悉了,Spring IoC的refresh的12大步;

四、Spring Boot启动流程图

95f93d9df7e30859e9407f96ae27fc65.png

分类: spring boot

最后,咱给小编:

1. 点赞+关注

2. 点头像关注后多多评论,转发给有需要的朋友。

谢谢!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值