前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot解决内、外tomcat部署兼容问题

SpringBoot解决内、外tomcat部署兼容问题

作者头像
Java深度编程
发布2020-06-10 16:14:32
2.5K0
发布2020-06-10 16:14:32
举报
文章被收录于专栏:Java深度编程Java深度编程

前言:

我们在使用springBoot开发的过程中出于方便,都会选择使用本地类Application中的main方法启动服务,即可实现本地的调试,十分的方便。但在线上环境需要放入外部的tomcat部署,这时候你会发现如果不做任何的处理是无法在外部tomcat启动的。

那么如何才能让springBoot项目才能在外部tomcat部署呢?这就涉及到启动入口,spring上下文对象的问题,我们本地之所以能通过main方法作为启动,是因为springBoot提供了一个此方式的上下文对象作为适配,通过SpringApplication.run调用了这个入口,进而使用内部的tomcat实现了服务的部署。之所以直接丢在外部tomcat无法启动,就是因为入口不同,驱动的时候做了适配的上下文。简而言之,入口是第一要素。所以既然外部tomcat启动没有入口,那我们就给它造一个入口。

实现外部的tomcat入口需要继承SpringBootServletInitializer,并重写configure方法,如下:

代码语言:javascript
复制
@SpringBootApplication
public class DemoApplication  extends SpringBootServletInitializer {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

  /**
   *提供外部tomcat启动入口
   */
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    // 注意这里要指向原先用main方法执行的Application启动类
    return builder.sources(DemoApplication.class);
  }
}

或者你可以新建一个类,与原Application类分开,如下:

以上就是实现外部tomcat入口的方式,按此方式即可实现外部tomcat部署了。

在网上有很多人写博客都指出了要排除web包下的tomcat依赖:

代码语言:javascript
复制
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <!-- 移除嵌入式tomcat插件 -->
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

如果你真的这么做了以后,你就被坑了。你会发现,虽然外部tomcat能部署了,但无法再同步本地java的main方法部署了,那么开发环境,和线上环境将会变得很麻烦。往往这些写这种博客的人只稀里糊涂的说要移除这个web包下的tomcat,却又不告诉你怎么解决本地无法启动的问题。之所以本地无法启动正是因为tomcat被移除了,没有了tomcat你还怎么启动呢!所以这时候就会又有文章来告诉你,要再加一个tomcat:

代码语言:javascript
复制
<!--spring-boot 内嵌tomcat主依赖, 方便本地调试
        (移除web包下的tomcat后需要此包本地才能启动)-->
    <!--兼容继承SpringBootServletInitializer外部tomcat启用-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>1.5.9.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

这些解决方案在网上都能找到,但鲜有人告诉你这其中的本质是什么,看到这些文章的人总会以为是因为要兼容外部的tomcat,所以要移除本地的tomcat,如果你这么想就错了。你反过来想想也就明白了,如果web包下的tomcat能引起和外部tomcat的冲突,那么又导入了spring-boot-starter-tomcat怎么就没冲突呢!事实说明其实根本就不存在所谓的冲突!前面说过部署的第一关是入口,入口不同使用了不同的适配上下文对象,所以它们是不会冲突的。

也就是说其实根本就不需要导入spring-boot-starter-tomcat,只要不排除web包下的tomcat,依然能够实现本地main方法,和外部tomcat的部署的兼容性问题。

而还有些项目中既没有排除web包下的tomcat,又同时导入了spring-boot-starter-tomcat,同样也能实现本地main方法,和外部tomcat的部署,这又是怎么回事呢?很多人很疑惑存在两个tomcat不会冲突吗?加上外部部署的tomcat就三个tomcat了,为何能够实现兼容?

首先前面说过内部与外部tomcat部署的入口不同,上下文的适配不同,因此不会冲突,那又该怎么解释内部的两个tomcat也不冲突呢?这就要说到maven依赖传递的问题了。

在maven有直接依赖和间接依赖这两种,A依赖B,B依赖C,那么A直接依赖B,B直接依赖C,而A则是间接依赖C,那么他们之间的依赖就有一条路线 A --> B --> C,此路线被称为依赖路径,如果遇到相同的依赖,则根据路径最短优先

也就是说根据上面的规则,假如再出现一个依赖C2,且C2 = C,具有C一样的功能和类,并且A依赖C2,那么当A需要C下的功能时,它有两个选择C和C2这时候有两条路径 1.A --> B --> C ; 2. A --> C2 。规则路径最短优先原则,那么A会选择C2作为依赖选取,从而遗弃C。这也就能解释为什么web下的tomcat和导入的spring-boot-starter-tomcat为什么能够共存而不引起冲突,那是因为压根就轮不到web下的tomcat起作用,当导入了spring-boot-starter-tomcat后,有没有web下的tomcat已经无所谓了,所以你排不排除它都没关系了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java深度编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档