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加,我们现在这么猜想完全是有可能的,带着这个猜想我们下一章来展开进行源码分析

浙公网安备 33010602011771号