springboot整合springmvc源码分析(1)--前言

springboot是怎么做到内嵌tomcat,而不需要去部署项目到tomcat的,在分析springboot整合springmvc前,我们先来说说一点关于tomcat的东西,我们这里不需要下载tomcat服务,只需要new 一个tomcat 即可,下面我们来一个例子看看

<dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-core</artifactId>
      <version>8.5.28</version>
    </dependency>
<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
public class App {
    public static void main(String[] args) throws LifecycleException, ServletException {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8989);
        tomcat.addWebapp("/","d:\\tomcat\\");
        tomcat.start();
        tomcat.getServer().await();
    }
}

 

我们只需要这样做就完全可以启动一个tomcat了

tomcat在启动过程中呢会自动加载实现了该接口ServletContainerInitializer的类,其中涉及到spi(不懂的自行百度),tomcat启动过程中会通过spi去加载实现ServletContainerInitializer的类的onStartup方法,spi默认文件结构:META-INF/services/javax.servlet.ServletContainerInitializer

只需要这样写即可完成spi的调用,该文件内容写上自己实现ServletContainerInitializer的类全名:

我们下面来试一下这种写法

1.实现ServletContainerInitializer接口:

@HandlesTypes(MyWebApplicationInitializerInterFace.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println("MyServletContainerInitializer.onStartup");
        for(Class<?> clz : c){
            System.out.println("MyServletContainerInitializer.onStartup:"+clz.getName());
            try {
                MyWebApplicationInitializerInterFace webApplicationInitializer = (MyWebApplicationInitializerInterFace)clz.newInstance();
                webApplicationInitializer.onStartup(ctx);
            } catch (Throwable ex) {
                throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
            }
        }
    }
}

这里有个@HandlesTypes注解,该注解意思是将所有MyWebApplicationInitializerInterFace.class实现该接口的类注入到onStartup方法里的参数Set<Class<?>> c里;

 2.编写MyWebApplicationInitializerInterFace接口:

public interface MyWebApplicationInitializerInterFace {
    void onStartup(ServletContext ctx);
}

3.实现MyWebApplicationInitializerInterFace接口:

public class MyWebApplicationInitializer implements MyWebApplicationInitializerInterFace{
    public void onStartup(ServletContext ctx) {
        ServletRegistration.Dynamic registration = ctx.addServlet("demo", new HttpServlet() {
            @Override
            public void init() throws ServletException {
                super.init();
                System.out.println("====init");
            }

            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                System.out.println("====doGet"+req.getRequestURI());
                resp.getWriter().println("hello tomcat!");
            }
        });
        registration.setLoadOnStartup(1);
        registration.addMapping("*.do");
    }
}

4.再次启动我们前面编写的tomcat的类App:

你会发现打印我我们加的日志,这就表明我们spi调用时成功的,MyWebApplicationInitializer 是自己写的添加一个HttpServlet放入tomcat中,注意App类这里tomcat.addWebapp("/","d:\\tomcat\\");写成tomcat.addContext("/","d:\\tomcat\\")也是可以,但是你会发现写成tomcat.addContext不会spi加载,写成tomcat.addWebapp实则是告诉tomcat我们是web服务

5.浏览器访问:

写到这里,不知大家能不能感受到springboot整合springmvc是否也是借此方式进行的呢?MyWebApplicationInitializer里添加的HttpServlet就好比springmvc的核心控制器DispatcherServlet往tomcat加,我们现在这么猜想完全是有可能的,带着这个猜想我们下一章来展开进行源码分析

posted @ 2020-04-11 15:18  menco  阅读(21)  评论(0)    收藏  举报