springboot是怎么做到内嵌tomcat,而不需要去部署项目到tomcat的,在分析springboot整合springmvc前,我们先来说说一点关于tomcat的东西,我们这里不需要下载tomcat服务,只需要new 一个tomcat 即可,下面我们来一个例子看看
org.apache.tomcat.embed tomcat-embed-core 8.5.28javax.servlet javax.servlet-api 3.1.0provided
public class App { public static void main(String[] args) throws LifecycleException, ServletException { Tomcat tomcat = new Tomcat(); tomcat.setPort(8989); tomcat.addWebapp("/","d:omcat"); 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> 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> 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:omcat");写成tomcat.addContext("/","d:omcat")也是可以,但是你会发现写成tomcat.addContext不会spi加载,写成tomcat.addWebapp实则是告诉tomcat我们是web服务
5.浏览器访问:
写到这里,不知大家能不能感受到springboot整合springmvc是否也是借此方式进行的呢?MyWebApplicationInitializer里添加的HttpServlet就好比springmvc的核心控制器DispatcherServlet往tomcat加,我们现在这么猜想完全是有可能的,带着这个猜想我们下一章来展开进行源码分析