1、前言
Springboot
默认的打包方式是jar
的方式。启动方式也比较简单java -jar xxx.jar
。但是很多时候,我们会针对老项目的改造,老项目都是使用传统的war
借助tomcat
启动。可能原来的tomcat
中配置茫茫复杂的东西,如分布式session、调优参数等。下来一起看看Springboot
是如何打成war
的。
2、官方文档解释
本文以springboot 1.5.10.RELEASE
为例。
文章中介绍了如何创建一个发布的war
包文件。
第一步:需要继承
SpringBootServletInitializer
第二步:重写
configure
方法,参数为当前启动类的Class即可第三步:修改pom文件
<packaging>war</packaging>
第四步:将内置的tomcat的生命周期标记为编译期可用,
<scope>provided</scope>
到这里Springboot
的war
包形式就打好了,可以愉快的部署发布了。
以上的打包方式都是基于官方文档中Servlet 3.0
的方式打包的,同时官方还对更低版本的Servlet 2.5
做了说明,有兴趣的可以去看看。
3、遇到的问题以及解决
Springboot 1.5.10.RELEASE
这个版本默认的内置tomcat的版本是8.5.27
由于老项目都是部署在tomcat7
的,所以打成war
后想部署在tomcat7
上。就会出现版本不兼容的问题。
直接使用外部的tomcat7启动,非常丝滑可以正常启动,但是有瑕疵。
启动成功后可以正常访问,但是启动日志会报错,就是Tomcat7
不能解析部分jar
中的字节码。
日志中就表示解析不了byte-buddy-agent-1.14.11
,只需要降低byte-buddy-agent
版本即可。
笔者遇到的包括:fastjson2
,guava
高版本均会编译报错。降低版本后问题解决。
直接使用tomcat8部署也是没有问题,会避免这些问题。
4、使用War启动的原理
Servlet容器
启动使用了SPI的机制。会加载org.springframework.web.SpringServletContainerInitializer
SpringServletContainerInitializer
上面标注了注解@HandlesTypes
,再启动的时候自行加载实现org.springframework.web.WebApplicationInitializer
这个接口的类。将实现类字节码集合的方式传入onStartup
方法,然后再分别调用各自的onStartup
方法。
WebApplicationInitializer
中有唯一的方式方法onStartup
方法。可以用来配置servlet
、filters
、上下文参数
等
SpringBootServletInitializer
实现了 WebApplicationInitializer
,自然也会执行相应的onStartup
方法。
创建web容器。主要代码块
-
builder.main(getClass())
,传入Main
方法。 -
builder = configure(builder)
Springboot
使用war
启动要重新的方法,传入当前类的字节码 -
configure
方法是用来给父子容器使用的。再启动过程中会发现,不重写该方法依然可以正常启动并访问。
具体创建Web容器的源码:
5、番外
在使用springboot 1.5.10.RELEASE
jar
启动之后遇到的问题:
-
搭配SpringCloud微服务时,第一次访问会比较慢,后面就正常了
-
使用
Springboot
启动时,客户端调用时,部分接口会出现不定时的超时。
目前不知道具体的原因。解决方案也是从jar
改成war
启动后,这些问题就解决了。有知道大佬,可以留言交流。
流。