欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot 嵌入式web容器的启动原理详解

程序员文章站 2022-04-10 12:44:52
目录springboot应用启动run方法springapplication.java 中执行的代码servletwebserverapplicationcontext.java执行的方法spring...

springboot应用启动run方法

springapplication.java 中执行的代码

@springbootapplication
@enableasync //使用异步注解@async 需要在这里加上@enableasync
@mapperscan("springboot.dao") //不可或缺作用是扫描dao包下面的所有mapper装配
public class helloapplication {
    public static void main(string[] args) {
        springapplication.run(helloapplication.class,args);
    }
}
    public static configurableapplicationcontext run(class<?> primarysource, string... args) {
        return run(new class[]{primarysource}, args);
    }
    public static configurableapplicationcontext run(class<?>[] primarysources, string[] args) {
        return (new springapplication(primarysources)).run(args);
    }

SpringBoot 嵌入式web容器的启动原理详解

 private void refreshcontext(configurableapplicationcontext context) {
        this.refresh(context);
        if (this.registershutdownhook) {
            try {
                context.registershutdownhook();
            } catch (accesscontrolexception var3) {
            }
        }
    protected void refresh(applicationcontext applicationcontext) {
        assert.isinstanceof(abstractapplicationcontext.class, applicationcontext);
        ((abstractapplicationcontext)applicationcontext).refresh();
    }

servletwebserverapplicationcontext.java执行的方法

    public final void refresh() throws beansexception, illegalstateexception {
        try {
            super.refresh();
        } catch (runtimeexception var2) {
            this.stopandreleasewebserver();
            throw var2;
        }
    }
    protected void onrefresh() {
        super.onrefresh();
        try {
            this.createwebserver();
        } catch (throwable var2) {
            throw new applicationcontextexception("unable to start web server", var2);
        }
    }
 private void createwebserver() {
        webserver webserver = this.webserver;
        servletcontext servletcontext = this.getservletcontext();
        if (webserver == null && servletcontext == null) {
            servletwebserverfactory factory = this.getwebserverfactory();
            this.webserver = factory.getwebserver(new servletcontextinitializer[]{this.getselfinitializer()});
        } else if (servletcontext != null) {
            try {
                this.getselfinitializer().onstartup(servletcontext);
            } catch (servletexception var4) {
                throw new applicationcontextexception("cannot initialize servlet context", var4);
            }
        }
        this.initpropertysources();
    }
    protected servletwebserverfactory getwebserverfactory() {
        string[] beannames = this.getbeanfactory().getbeannamesfortype(servletwebserverfactory.class);
        if (beannames.length == 0) {
            throw new applicationcontextexception("unable to start servletwebserverapplicationcontext due to missing servletwebserverfactory bean.");
        } else if (beannames.length > 1) {
            throw new applicationcontextexception("unable to start servletwebserverapplicationcontext due to multiple servletwebserverfactory beans : " + stringutils.arraytocommadelimitedstring(beannames));
        } else {
            return (servletwebserverfactory)this.getbeanfactory().getbean(beannames[0], servletwebserverfactory.class);
        }
    }
    //配置嵌入式的servlet容器
    @bean
    public webserverfactorycustomizer<configurablewebserverfactory> mycustomizer(){
        return new webserverfactorycustomizer<configurablewebserverfactory>() {
            @override
            public void customize(configurablewebserverfactory factory) {
                factory.setport(8081);
            }
        };
    }

springboot 2.x 版本

嵌入式servlet容器自动配置原理以及启动原理

一、版本说明

spring boot 2.x 版本的嵌入式servlet容器自动配置是通过 webserverfactorycustomizer定制器 来定制的,而在spring boot 1.x 版本中我们是通过 embeddedservletcontainercustomizer 嵌入式的servlet容器定制器来定制的。由于之前看的资料都是1.x的版本,但是我使用的是2.x,所以在这里记录一下2.x版本的嵌入式servlet容器自动配置原理以及启动原理。

二、总结

嵌入式servlet容器自动配置原理以及启动原理有三大步:

步骤:

  • springboot 根据导入的依赖信息,自动创建对应的 webserverfactorycustomizer(web服务工厂定制器);
  • webserverfactorycustomizerbeanpostprocessor(web服务工厂定制器组件的后置处理器)获取所有类型为web服务工厂定制器的组件(包含实现webserverfactorycustomizer接口,自定义的定制器组件),依次调用customize()定制接口,定制servlet容器配置;
  • 嵌入式的servlet容器工厂创建tomcat容器,初始化并启动容器。

三、嵌入式servlet容器自动配置原理(以tomcat为例)

1、首先找到 embeddedwebserverfactorycustomizerautoconfiguration ,在里面我们可以看到springboot支持的 servlet容器

//sprinboot支持的servlet容器有三个tomcat、jetty、undertow,但是默认配置的是tomcat
 
 
//嵌入式的undertow
    @configuration(
        proxybeanmethods = false
    )
    @conditionalonclass({undertow.class, sslclientauthmode.class})
    public static class undertowwebserverfactorycustomizerconfiguration {
        public undertowwebserverfactorycustomizerconfiguration() {
        }
 
        @bean
        public undertowwebserverfactorycustomizer undertowwebserverfactorycustomizer(environment environment, serverproperties serverproperties) {
            return new undertowwebserverfactorycustomizer(environment, serverproperties);
        }
    }
 
 
//嵌入式的jetty
    @configuration(
        proxybeanmethods = false
    )
    @conditionalonclass({server.class, loader.class, webappcontext.class})
    public static class jettywebserverfactorycustomizerconfiguration {
        public jettywebserverfactorycustomizerconfiguration() {
        }
 
        @bean
        public jettywebserverfactorycustomizer jettywebserverfactorycustomizer(environment environment, serverproperties serverproperties) {
            return new jettywebserverfactorycustomizer(environment, serverproperties);
        }
    }
 
//嵌入式的tomcat
    @configuration(
        proxybeanmethods = false
    )
    @conditionalonclass({tomcat.class, upgradeprotocol.class})
    public static class tomcatwebserverfactorycustomizerconfiguration {
        public tomcatwebserverfactorycustomizerconfiguration() {
        }
 
        @bean
        public tomcatwebserverfactorycustomizer tomcatwebserverfactorycustomizer(environment environment, serverproperties serverproperties) {
            return new tomcatwebserverfactorycustomizer(environment, serverproperties);
        }
    }

2、准备环节

1)在以下位置打一个断点

SpringBoot 嵌入式web容器的启动原理详解

2)、点进 tomcatwebserverfactorycustomizer 也就是上图 return 的,然后在里面的如下位置打一个断点

SpringBoot 嵌入式web容器的启动原理详解

3)、然后在里面debug程序,我们在控制台就可以看到如下信息

SpringBoot 嵌入式web容器的启动原理详解

3、按照上图从下往上分析。我们启动springboot应用时,都是直接运行主程序的main方法,然后调用里面的run方法,如下图

SpringBoot 嵌入式web容器的启动原理详解

4、调用完run方法,回来到 refreshcontext 方法,这个方法是帮我们创建ioc容器对象,并且初始化容器创建容器中的每一个组件

SpringBoot 嵌入式web容器的启动原理详解

5、在调用了 reflesh 方法刷新刚才的ioc容器后,来到 onreflesh 方法,调用createwebserver()方法,创建webserver

SpringBoot 嵌入式web容器的启动原理详解

6、来到createwebserver()方法,该方法最终能够获取到一个与当前应用(也就是总结里说的第一步,根据我们导入的依赖来获取)所导入的servlet类型相匹配的web服务工厂,通过工厂就可以获取到相应的 webserverfactorycustomizer (web服务工厂定制器)

注:createwebserver()执行后,我们其实来到了 embeddedwebserverfactorycustomizerautoconfiguration,然后根据条件(配置的依赖)配置哪一个web服务器

SpringBoot 嵌入式web容器的启动原理详解

我们通过查看 servletwebserverfactory 的子类,可以看到其中三个就是tomcat、jetty和undertow,根据我们的配置,所以这里获取到的是 tomcatwebserverfactorycustomizer

SpringBoot 嵌入式web容器的启动原理详解

至此,tomcatwebserverfactorycustomizer组件创建完成,对应的服务配置类也已添加到ioc容器。

7、因为容器中某个组件要创建对象就会惊动后置处理器 然后就到 webserverfactorycustomizerbeanpostprocessor(web服务工厂定制器组件的后置处理器),该类负责在bean组件初始化之前执行初始化工作。它先从ioc容器中获取所有类型为webserverfactorycustomizerbeans(web服务工厂定制器的组件)

SpringBoot 嵌入式web容器的启动原理详解

通过后置处理器获取到的tomcatwebserverfactorycustomizer调用customize()定制方法,获取到servlet容器相关配置类serverproperties,进行自动配置

SpringBoot 嵌入式web容器的启动原理详解

至此,嵌入式servlet容器的自动配置完成。

注:从源码分析可以得出配置嵌入式servlet容器的两种解决方案:

1、在全局配置文件中,通过server.xxx来修改和server有关的配置:

server.port=8081
server.tomcat.xxx...

2、实现webserverfactorycustomizer接口,重写它的customize()方法,对容器进行定制配置:

@functionalinterface
public interface webserverfactorycustomizer<t extends webserverfactory> {
    void customize(t factory);
}

四、嵌入式servlet容器启动原理(以tomcat为例)

1、应用启动后,根据导入的依赖信息,创建了相应的servlet容器工厂,创建了tomcatservletwebserverfactory,调用getwebserver()方法创建tomcat容器:(其实就是重写了servletwebserverfactory里面的getwebserver方法

SpringBoot 嵌入式web容器的启动原理详解

找到下面的gettomcatwebserver方法

SpringBoot 嵌入式web容器的启动原理详解

2、然后点进去分析tomcatwebserver的有参构造器,执行 initialize() 方法

SpringBoot 嵌入式web容器的启动原理详解

3、点进去就可以发现,里面通过调用start方法来启动tomcat

SpringBoot 嵌入式web容器的启动原理详解

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

上一篇: WCF初识

下一篇: 快被她折腾光了