将 Spring Boot 部署到 Tomcat

Posted

技术标签:

【中文标题】将 Spring Boot 部署到 Tomcat【英文标题】:Deploy Spring Boot to Tomcat 【发布时间】:2014-09-04 16:21:09 【问题描述】:

所以我是 Spring 新手 - 所以我想我会尝试 Spring Boot

我正在使用 Maven 构建 - 我设置了一个视图请求,当我运行它时,“App”看起来像是它自己启动了 Tomcat,并且我在默认的 8080 端口有一个服务,所以当我调用 localhost:8080/service一切都好。

但是,当我尝试将其打包为 WAR 以部署到服务器时,它不起作用

所以我想我会回到基础并将其部署到本地的 tomcat 服务器上,看看会发生什么

所以首先什么都没发生 - 404 - 做了一些谷歌搜索发现我需要包含这样的网络入口点 - 这是我的主要课程

@ComponentScan
@EnableAutoConfiguration
public class App extends SpringBootServletInitializer


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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) 
        return application.sources(appClass);
    

    private static Class<App> appClass = App.class;

所以它看起来像它工作,在控制台中我可以看到红色的 catalina 启动文本,然后我看到 Spring boot 启动(我以前没有看到)

但是,当我尝试调用服务 localhost:8080/service 时,我仍然收到 404

当我将它作为“应用程序”运行时,它会起作用

有什么明显的事情我需要做的吗?我只是制造战争

    将 pom xml 包类型更改为 war 在上面的代码 sn-p 中包含了覆盖 作为战争输出

我已经解压缩了 WAR,它看起来很好 - 有一个 WEB-INF 和一组依赖项等。

任何帮助都会很好 - 因为有人在将 Spring Boot 应用程序部署为 WAR 时遇到类似问题?

***更新****

现在我可以让我的战争在我的本地 Tomcat 7 服务器上正确部署 - 但是当我尝试部署到外部托管的 Tomcat 容器时,我得到了

at       org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 15 more
Jul 14, 2014 1:49:01 PM org.apache.catalina.startup.HostConfig deployDirectory
SEVERE: Error deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/cookpot
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/cookpot]]
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:898)
at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:130)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:153)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:142)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:869)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1095)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1617)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Jul 14, 2014 1:49:01 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/examples
Jul 14, 2014 1:49:01 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/host-manager
Jul 14, 2014 1:49:01 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/CookPot
Jul 14, 2014 1:49:02 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/usr/local/shared/tomcat/thecookpot/webapps/CookPot/WEB-INF/lib/tomcat-embed-core-7.0.52.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
Jul 14, 2014 1:49:02 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/usr/local/shared/tomcat/thecookpot/webapps/CookPot/WEB-INF/lib/tomcat-embed-el-7.0.52.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/el/Expression.class
Jul 14, 2014 1:49:06 PM org.apache.catalina.core.ContainerBase addChildInternal
SEVERE: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/CookPot]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:895)
at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:130)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:153)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:142)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:869)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1095)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1617)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.security.AccessControlException: access denied (java.util.PropertyPermission java.awt.headless write)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.System.setProperty(System.java:727)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:263)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:130)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:89)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:51)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5262)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 15 more
Jul 14, 2014 1:49:06 PM org.apache.catalina.startup.HostConfig deployDirectory
SEVERE: Error deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/CookPot
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/CookPot]]
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:898)
at org.apache.catalina.core.ContainerBase.access$000(ContainerBase.java:130)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:153)
at org.apache.catalina.core.ContainerBase$PrivilegedAddChild.run(ContainerBase.java:142)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:869)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1095)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1617)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Jul 14, 2014 1:49:06 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/ROOT
Jul 14, 2014 1:49:06 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/manager
Jul 14, 2014 1:49:06 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/docs
Jul 14, 2014 1:49:06 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory /usr/local/shared/tomcat/thecookpot/webapps/Cookpot
Jul 14, 2014 1:49:06 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/usr/local/shared/tomcat/thecookpot/webapps/Cookpot/WEB-INF/lib/tomcat-embed-core-7.0.52.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
Jul 14, 2014 1:49:06 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/usr/local/shared/tomcat/thecookpot/webapps/Cookpot/WEB-INF/lib/tomcat-embed-el-7.0.52.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/el/Expression.class
Jul 14, 2014 1:49:09 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-6350"]
Jul 14, 2014 1:49:09 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-4350"]
Jul 14, 2014 1:49:09 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 17529 ms

【问题讨论】:

你有没有运行“mvn package”来创建.war?另外,在您的pom.xml 中,您是否将spring-boot-starter-tomcat 标记为provided?请参阅here 了解此内容。 一般来说,Tomcat 会在你的应用程序的 URL 前加上 appname/。应用程序的 Tomcat 名称是什么? 您是否遵循了 Spring.io 上的指南,该指南描述了如何将您的应用程序打包为 WAR 并部署到 Tomcat? spring.io/guides/gs/convert-jar-to-war @philthomas26 你能准确解释一下你是如何解决这个问题的吗?因为我也一样。提前谢谢你 我以前遇到过这个问题,可以确认接受的解决方案有效。我也没有使用 Gradle 遇到过,因此也可以使用 Gradle 代替 Maven。 【参考方案1】:

当我们选择 Spring Boot 时,我们不想产生 WAR。来自root page:

Spring Boot makes it easy to create stand-alone [...] 
Applications that can you can "just run".
Embed Tomcat or Jetty directly (no need to deploy WAR files)

编辑: 所以,如果目的是“尝试 Spring Boot”,我建议不要生成 WAR 文件。

如果您确实需要生成 WAR 文件(保持您的代码针对 SpringBoot 构建并生成可以在任何标准 servlet 容器中运行的文件...),那么您应该阅读文档Converting a Spring Boot JAR Application to a WAR。

您是否在构建过程中包含 spring-boot-maven-plugin ?你没有描述这一步...

【讨论】:

如果您发布一个有关如何正确执行此操作的相关示例会有所帮助 @staticx 可以在 Spring 的网站上找到:convert Spring Boot JAR to WAR。但在我看来,mcoolive 实际上确实比詹姆斯更好地回答了这个问题,考虑到没有人提到这个问题很奇怪。 Spring Boot 的全部意义在于运行一个简单的 jar 文件。仅当您使用 java servlet 容器(例如 tomcat)时才会生成 war 文件。有关这方面的更多信息,请查看:spring.io inside and out 这条评论没有回答问题。 cmets一般会回答问题吗? 此“答案”仅提供作者对他是否认为 OP 的目标合理与否的意见。【参考方案2】:

Spring Boot 参考文档中的章节Packaging executable jar and war files 指出:

要构建一个既可执行又可部署到外部容器的 war 文件,您需要将嵌入式容器依赖项标记为“已提供”,例如:

<?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- ... -->
    <packaging>war</packaging>
    <!-- ... -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- ... -->
    </dependencies>
</project>

【讨论】:

我相信在mvn package 最终生成可部署到tomcat 的.war 之前,我必须mvn clean,同时应用此解决方案(它终于奏效了)。 “.war-ize”spring-boot 应用的步骤总结:(1)&lt;packaging&gt;war&lt;/packaging&gt;,以及pom.xml中带有“provided”的上述依赖,(2)修改Application.java extends SpringBootServletInitializer 和问题中的@Override。通过 java -jar 生成可运行的 .war 并使用 spring-boot 1.3.1 部署到 tomcat 7.0.59 和 jetty 9.3.6。 重要的是要注意spring-boot-maven-plugin构建插件应该调用目标repackageSee doc。【参考方案3】:

以下代码适用于不依赖 tomcat 的 tomcat8 部署。

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
public class ManufacturingRegionApplication extends SpringBootServletInitializer 

public static void main(String[] args) 
    new SpringApplicationBuilder(ManufacturingRegionApplication.class).application().run(args);


@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) 
    return applicationBuilder.sources(application);


private static Class<ManufacturingRegionApplication> application = ManufacturingRegionApplication.class;

不需要以下依赖。

   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

 @RestController
 @RequestMapping(value = "/manufacturing-region-service")
 public class ManufacturingRegionService 

@Resource
private ManufacturingRegionDao manufacturingRegionDao;

@ResponseBody
@Transactional(readOnly = true)
@RequestMapping(value = "/region-codes/abbr", method = GET, produces = "application/json")

http://localhost:8080/manufacturing-region-api/manufacturing-region-service/region-codes/ABBRVALUE

【讨论】:

以上是关于将 Spring Boot 部署到 Tomcat的主要内容,如果未能解决你的问题,请参考以下文章

如何在外部 tomcat 中部署 Spring-boot REST API

尝试在外部在tomcat 9上运行带有rest控制器的spring boot war文件

Spring Boot REST Controller 部署在外部 tomcat 9 服务器上时返回 404

在外部 tomcat 中定义 Spring Boot 应用程序的上下文路径

将 Spring Boot 部署到 Tomcat

Spring boot 1.4登录外部tomcat