SpringBoot中SpringMVC 整合启动嵌入式Tomcat 原理及源码解析

SpringBoot 是微服务模式下 Spring的最佳实践方式,它整合了web 服务器,可以通过 Main 方法直接启动微服务。

SpringBoot 整合Tomcat原理:

1、Tomcat 是 JAVA 语言开发的应用程序 ,打包成应用程序它的启动入口是:BootStrap

      eval exec "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start

2、我们同样可以在 Java 代码中直接调用Tomcat 的 Start 方法来启动Tomcat,但是注意 启动之前要先配置Tomcat。Tomcat类和Bootstrap类的区别是:Tomcat类是作为嵌入式模式下最小配置启动入口,而Bootstrap是Tomcat作用独立应用时候的启动入口。

    public static void run() {
        System.out.println("app start...");

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8086);
        try {
            tomcat.addWebapp("/", "d:\\tom\\");
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException | ServletException e) {
            e.printStackTrace();
        }
    }

3、既然 Tomcat 是Servlet 服务器,那么我们代码中在启动Tomcat 之前将SpringMVC的 DispatcherServlet 配置好 交给 Tomcat 是不是就可以实现启动Web服务? 答案是肯定的。

PS:实现了ServletContainerInitializer 接口的具体类的onStartup函数会在Servlet 容器启动时自动被调用,从而实现了在方法内注册spring ioc容器以及DispatcherServlet。     Servlet 3.0 新增的一个ServletContainerInitializer接口,WEB容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer 的实现类的servlet配置,而WebApplicationInitializer是一个被委托接口。

源码:


//------------Spring 配置类--------------//
@Configuration
@ComponentScan("com.src")
public class AppConfig {
}

//-------------Servlet 3.0 -------------//
public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("====web init===");
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);

        DispatcherServlet dispatcherServlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletContext.addServlet("mvc", dispatcherServlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/*");
    }
}

//-------------TomcatRunner -------------//
public class TomcatRunner {

    public static void run() {
        System.out.println("app start...");

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8086);
        try {
            tomcat.addWebapp("/", "d:\\tom\\");
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException | ServletException e) {
            e.printStackTrace();
        }
    }
}

//-------------ApplicationStarter -------------//
public class ApplicationStarter {
    public static void main(String[] args) {
        TomcatRunner.run();
    }
}

//-------------RestController-------------//
@RestController
@RequestMapping("/hello")
public class HelloController {

    @GetMapping("/hi")
    public String hello() {
        return "ok";
    }
}

SpringBoot 整合Tomcat 领域模型设计(类图):

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5puy6YCfMTA3MQ==,size_20,color_FFFFFF,t_70,g_se,x_16

SpringBoot 整合Tomcat 源码解析:

@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
			return dispatcherServlet;
		} 

@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
					webMvcProperties.getServlet().getPath());
			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
			multipartConfig.ifAvailable(registration::setMultipartConfig);
			return registration;
		}

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

  protected void onRefresh() {
        super.onRefresh();

        try {
            // 从此处开始启动web服务器.
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }

SpringBoot 启动Tomcat 方法调用链:

start:486, Tomcat (org.apache.catalina.startup)
initialize:123, TomcatWebServer (org.springframework.boot.web.embedded.tomcat)
<init>:104, TomcatWebServer (org.springframework.boot.web.embedded.tomcat)
getTomcatWebServer:437, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
getWebServer:191, TomcatServletWebServerFactory (org.springframework.boot.web.embedded.tomcat)
createWebServer:178, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
onRefresh:158, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:545, AbstractApplicationContext (org.springframework.context.support)
refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:758, SpringApplication (org.springframework.boot)
refresh:750, SpringApplication (org.springframework.boot)
refreshContext:397, SpringApplication (org.springframework.boot)
run:315, SpringApplication (org.springframework.boot)
run:1237, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)

${纸上得来终觉浅!}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值