您现在的位置是:亿华云 > 数据库

如何给Spring Boot 的嵌入式 Tomcat 部署多个应用?

亿华云2025-10-03 06:57:15【数据库】0人已围观

简介Spring Boot 的应用,大都有这样的特别,你在添加了依赖之后,即使是 Web 应用,最终也可以通过 JAR 的形式运行,具体依赖的容器环境,则通过嵌入式的形式隐式的使用。而像这些环境,Spri

Spring Boot 的嵌多应用,大都有这样的入式特别,你在添加了依赖之后,部署即使是应用 Web 应用,最终也可以通过 JAR 的嵌多形式运行,具体依赖的入式容器环境,则通过嵌入式的部署形式隐式的使用。

而像这些环境,应用Spring 的嵌多配置等,更多的入式隐藏在 Spring Boot 的内部,开发者可以更多的部署专注于「业务逻辑」的开发。

「解放了双手」的应用时候,话说回来,嵌多某些时候,入式也是部署有一些弊端的。比如像之前通过 WAR 文件的形式独立部署时,可以在容器内再额外部署一些「监控」应用,来观察容器的站群服务器情况,应用的请求情况等,这些内容在嵌入式的时候,就有些办不从心了。

那对于 习惯了 Spring Boot 的 JAR 文件便捷运行的用户,有没有办法,能在保留 JAR 使用习惯的前提下,又能部署其他应用,来满足独立容器部署的形式和使用习惯呢?

答案是有的。鱼和熊掌,也可得兼。 后面我们会以嵌入式的 Tomcat 为例,来说明具体的实现方式。

首先,我们需要认识这一点,对于嵌入式的容器,他本质上依然还是容器,保留了容器的绝大数内容。所以,一些独立部署时的服务器租用风格,接口也依然可以使用。

不熟悉 Spring Boot 内 Tomcat 工作原理的读者,可以参考这几篇旧文:

Tomcat 是怎样处理 SpringBoot应用的? Tomcat 中 的可插拔以及 SCI 的实现原理 如何开发自己的 Spring Boot Starter

我们前面说,嵌入式容器,也还是容器,所以我们只要「拿到」这个容器,就可以对其进行操作了。

旧文里我们提过, Spring Boot 内的嵌入式 Tomcat,是自己 new 了一个Tomcat 实例出来,再把应用做为 Context 部署进去。我们要想部署其他的应用,也照着「葫芦」拿到 这个实例,部署应用。

Spring Boot 内,由于要支持各种 Servlet 容器,所以统一进行了抽象了创建容器的Factory,在 Spring Boot 1.x 和 2.x分别由

EmbeddedServletContainerFactory 和 ServletWebServerFactory 这两个接口表示。 而对应的工厂里创建出来的容器对象,亿华云计算在 1.x 和 2.x 中,分别由TomcatEmbeddedServletContainer 和 TomcatWebServer 这两个类来表示。

这个 Factory,也是做为一个 Bean 参与到Spring Boot 的启动流程中。我们需要做的,就是在启动的时候,定义这样一个Bean,并「重写」Factory 中可以拿到 Tomcat 实例的方法,拿到前面创建出来的 Tomcat 实例,即可完成应用的部署。

1.x 的方式如下:

@Bean     public EmbeddedServletContainerFactory servletContainerFactory() {          return new TomcatEmbeddedServletContainerFactory() {     protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(                     Tomcat tomcat) {                  new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();                 try {                      Context context = tomcat.addWebapp("/test", "/home/test/sample.war"); // 这里是要部署的应用名称和路径                     context.setParentClassLoader(getClass().getClassLoader());                 } catch (Exception ex) {                      throw new IllegalStateException("Failed to add webapp", ex);                 }                 return super.getTomcatEmbeddedServletContainer(tomcat);             }         };     } 

2.x

@Bean     public ServletWebServerFactory servletContainerFactory() {          return new TomcatServletWebServerFactory() {              protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {                  new File(tomcat.getServer().getCatalinaBase(), "hello").mkdirs();                 try {                      Context context =                             tomcat.addWebapp("/foo", "/home/test/sample.war");                     context.setParentClassLoader(getClass().getClassLoader());                 } catch (Exception ex) {                      throw new IllegalStateException("Failed to add webapp", ex);                 }                 return super.getTomcatWebServer(tomcat);             };         };     } 

当然,还有其它的方法也可以实现类似的目的。

比如,几年前的一篇旧文,在分析 IDE里 Tomcat 的工作原理的时候,分析过 IDEA 里, Tomcat 是怎样部署应用的。那个实现思路,是通过 Tomcat 注册的 MBean,其中包含对于应用管理的MBean,对于嵌入式的 Tomcat,也依然放开了 MBean Server, 连接到上面就可以部署应用了。需要注意的一点,是嵌入式的 Tomcat,Host 的ObjectName,和独立运行的并不一样,需要注意,否则会导致部署失败。

总结一下,嵌入式容器,也保留了独立部署容器的管理和使用习惯,在启动创建的过程中,可以获取其容器实例进行操作。也可以通过对外暴露的 MBean Server 进行操作。

【本文为专栏作者“侯树成”的原创稿件,转载请通过作者微信公众号『Tomcat那些事儿』获取授权】

戳这里,看该作者更多好文

很赞哦!(17)