如何將War檔案部署到Spring Boot嵌入式的Tomcat中 - Vojtech Ruzicka

banq發表於2019-10-12

預設情況下,Spring Boot在嵌入式Tomcat中以jar形式執行(儘管您可以將其部署為常規WAR)。與嵌入式應用程式伺服器一起執行非常好,但是有時您可能需要將另一場戰爭與嵌入式應用程式捆綁在一起。也許您有一箇舊版應用程式需要包括在內,但不想為此設定常規的Tomcat。

幸運的是,使用Spring Boot,這很容易。具體實現方式取決於您的Spring Boot版本。

Spring Boot 2.x

您需要做的就是在您的一個@Configurationtype類中宣告一個bean TomcatServletWebServerFactory。然後,您需要重寫getTomcatWebServer()方法。這樣增加war如同執行tomcat.addWebApp()一樣簡單。

請注意,在下面的示例中,webapps由於預設情況下該目錄不存在,因此需要建立該目錄。它是通常將war部署到Tomcat的目錄。

@Bean
public TomcatServletWebServerFactory servletContainerFactory() {
    return new TomcatServletWebServerFactory() {
    
      @Override
      protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
          // webapps directory does not exist by default, needs to be created
          new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
    
          // Add a war with given context path
          // Can add multiple wars this way with different context paths
          tomcat.addWebapp("context-path", "path-to-your-war.war");
    
          return super.getTomcatWebServer(tomcat);
      }
    
    };
}

您可以將它們外部化為屬性,而不必硬編碼WAR的路徑及其上下文路徑,並且僅在存在這些屬性時使用載入WAR(使用@ConditionalOnProperty)。

您可以將它們放入您application.properties的應用程式中,也可以在執行應用程式時將它們作為命令列引數傳遞。這樣,您可以例如在進行本地開發時跳過載入您的WAR,或者在不同的環境中提供不同的工件。

@Bean
@ConditionalOnProperty(name = "external.war.file")
public TomcatServletWebServerFactory servletContainerFactory(@Value("${external.war.file}") String path,
                                                             @Value("${external.war.context}") String contextPath) {
    return new TomcatServletWebServerFactory() {

        @Override
        protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
            new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();

            tomcat.addWebapp(contextPath, path);

            return super.getTomcatWebServer(tomcat);
        }

    };
}

如果要將WAR部署到/,則需要使用一個空字串作為上下文根。為了避免與Spring Boot應用程式發生衝突,可以application.properties通過設定來更改其上下文根server.servlet.context-path。

使用胖JAR中的依賴項

如果要避免兩個工件都使用重複的依賴關係,則可以指定外部WAR應使用胖JAR的類載入器。

Context context = tomcat.addWebapp("context-path", "path-to-your-war.war");
context.setParentClassLoader(getClass().getClassLoader());

Spring Boot 1.x

Spring Boot 2.x進行了大量的重構,在執行Spring Boot 1.x時,您需要使用其他類來部署WAR。還請注意該try-catch塊,這對於捕獲方法丟擲的已檢查異常是必需的。

@Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
    return new TomcatEmbeddedServletContainerFactory() {

        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                Tomcat tomcat) {

            new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
            
            try {
                tomcat.addWebapp("context-path", "path-to-your-war.war");
            } catch (ServletException e) {
                log.error("Unable to deploy war to embedded Tomcat");
            }

            return super.getTomcatEmbeddedServletContainer(tomcat);
        }

    };
}

如果您想更改Spring Boot應用程式的上下文路徑,則該過程與2.x相同,除了其中的屬性名稱application.properties不同,這也適用於1.x版本server.context-path。

新增對JSP的支援

如果您的外部非Spring Boot WAR包含JSP,則需要確保為其提供適當的依賴項,因為嵌入式Tomcat預設情況下不包含它們。對於Maven,您可以使用:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>

對於Gradle,請改用以下程式碼:

compile "org.apache.tomcat.embed:tomcat-embed-jasper"
compile "javax.servlet:jstl"

 

相關文章