一、介绍
一般我们启动web服务都需要单独的去安装tomcat,而Springboot自身却直接整合了Tomcat,什么原理呢?
二、原理
SpringBoot应用只需要引入spring-boot-starter-web中这个依赖,应用程序就默认引入了tomcat依赖,其实这主要是Tomcat本身提供的外部接口(org.apache.catalina.startup.Tomcat),使其它应用程序能够非常方便的将Tomcat嵌入到自身的应用来。
下面是从网络上找的一个自身的程序嵌入如何实现嵌入式Tomcat,达到和Springboot类似的效果:
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</dependency>
定义一个简单的一个servlet类(提供web服务):
public class DemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html><html>");
out.println("<head>");
out.println("<meta charset="UTF-8" />");
out.println("<title></title>");
out.println("</head>");
out.println("<body bgcolor="white">");
out.println("<h1> 嵌入式tomcat</h1>");
out.println("</body>");
out.println("</html>");
}
}
定义一个EmbeddedTomcatServer类,主程序执行入口:
EmbeddedTomcatServer类作为程序的入口,代码逻辑其实就是通过tomcat提供的外部接口类修改server.xml这个文件;
public class EmbeddedTomcatServer {
public static void main(String[] args) throws Exception {
//把目录的绝对的路径获取到
String classpath = System.getProperty("user.dir");
System.out.println(classpath);
//new一个Tomcat
Tomcat tomcat = new Tomcat();
//插件是6或者6以前的
//Embbedded
//设置Tomcat的端口
//tomcat.setPort(9090);
Connector connector = tomcat.getConnector();
connector.setPort(9091);
//设置Host
Host host = tomcat.getHost();
//我们会根据xml配置文件来
host.setName("localhost");
host.setAppBase("webapps");
//前面的那个步骤只是把Tomcat起起来了,但是没啥东西
//要把class加载进来,把启动的工程加入进来了
Context context = tomcat.addContext(host, "/", classpath);
if (context instanceof StandardContext) {
StandardContext standardContext = (StandardContext) context;
standardContext.setDefaultContextXml("E:\apache-tomcat-8.5.51\conf\web.xml");
//我们要把Servlet设置进去
Wrapper wrapper = tomcat.addServlet("/", "DemoServlet", new DemoServlet());
wrapper.addMapping("/embeddedTomcat");
}
//Tomcat跑起来
tomcat.start();
//强制Tomcat server等待,避免main线程执行结束后关闭
tomcat.getServer().await();
}
}
三、SpringBoot接入原理
SpringBoot嵌入Tomcat的原理其实和上面的案例是一样的,我们来看下代码:
首先进入run方法,并点击refreshContext(context)方法:
如下可知,底层就是用的Tomcat类实现。
四、springboot中springmvc的初始过程
首先,在ServletWebServerApplicationContext的refresh的方法中,会调用createWebServer()方法来创建webServer org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh。
看一下createWebServer方法,首先会判断servletContext是否为空,如果为空,则会先获取ServletWebServerFactory,再进行初始化
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
在getSelfInitializer()中,会进行ServletContextInitializer的初始化,在getServletContextInitializerBeans中,在此方法中,通过调用new ServletContextInitializerBeans获取到一个List<ServletContextInitializer>数组,其中就包括了我们熟知的DispatchServlet和定义的Filter等等。
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
beans.onStartup过程中,进行了servlet和filter的注册,这个过程在org.springframework.boot.web.servlet.DynamicRegistrationBean#register方法中进行,会将servlet加入到servletContext中,或者将filter加入servletContext中去。
从启动日志也可以看大概的流程:
版权声明:本文为CSDN博主「小魏的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:总结:SpringBoot内嵌Tomcat原理_小魏的博客的博客-CSDN博客
相关文章: