问题描述
我正在开发一个需要在我们客户端的 Tomcat 服务器上运行的 Java Spring Boot 应用程序.此应用程序基本上包含一个 REST API,用于向我们的前端提供文件.
I'm developing a Java Spring Boot application that needs to run on our client's Tomcat server. This application basically contains a REST API that serves files to our frontend.
在我们第一次在客户端的服务器上进行部署测试之前,在本地运行此应用程序一直很顺利.我们不得不重构我们的代码并向项目的 pom.xml 添加一些依赖项.这最终奏效了(有点).
Running this application locally went great until our first deployment testing on the client's servers. We had to refactor our code and add some dependencies to the projects' pom.xml. This eventually worked (kind of).
现在我想再次开始本地开发,并注意到我的代码无法使用我之前使用的相同运行配置运行.虽然执行 mvn spring-boot:run
工作正常,但我需要 IntelliJ 的调试功能才能继续开发.
Now I wanted to again start developing locally and noticed my code wasn't able to run with the same run config I used before. While executing mvn spring-boot:run
worked fine, I needed IntelliJ's debug functionality to be able to proceed development.
经过一番搜索,我在我的 pom.xml 中发现了这个问题:
After some searching I identified the issue in my pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
虽然 是在 tomcat 上运行生成的 WAR 文件所必需的,但我在本地运行时遇到了一些问题.更具体地说,产生了以下错误:
While the <scope>provided</scope>
was necessary to run the generated WAR file on the tomcat, I gave some issues running locally. To be more specific, following errors were generated:
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.context.annotation.AnnotationConfigApplicationContext@2a693f59: startup date [Mon Nov 06 10:52:25 CET 2017]; root of context hierarchy
at Org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:414) [spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.ApplicationListenerDetector.postProcessBeforeDestruction(ApplicationListenerDetector.java:97) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:253) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:961) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.destroySingletons(FactoryBeanRegistrySupport.java:230) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:968) [spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1030) [spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:556) [spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at be.craftworkz.engima.acerta.boilerplate.BoilerplateApplication.main(BoilerplateApplication.java:23) [classes/:na]
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [be.craftworkz.engima.acerta.boilerplate.BoilerplateApplication]; nested exception is java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.boot.web.support.SpringBootServletInitializer
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:181) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at be.craftworkz.engima.acerta.boilerplate.BoilerplateApplication.main(BoilerplateApplication.java:23) [classes/:na]
Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.boot.web.support.SpringBootServletInitializer
at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:163) ~[spring-core-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.retrieveBeanMethodMetadata(ConfigurationClassParser.java:380) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:314) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:198) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
... 12 common frames omitted
Caused by: java.lang.NoClassDefFoundError: javax/servlet/ServletContext
at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_144]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_144]
at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_144]
at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:152) ~[spring-core-4.3.12.RELEASE.jar:4.3.12.RELEASE]
... 17 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_144]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_144]
... 21 common frames omitted
从我的依赖项中删除这个 解决了这个问题,但我不明白这里的问题是什么.因此,如果有人可以详细解释为什么会发生此错误,那就太棒了!我真的很想避免将来在这些问题上浪费时间,所以......
Removing this <scope>provided</scope>
from my dependency solved the issue but I don't understand what the problem is here. So if someone could give a detailed explanation why this error occurs that would be awesome! I really want to avoid losing time to these kind of issues in the future so ...
谢谢!
TL;博士:Maven 依赖项参数 provided</scope>
如何影响在本地和远程在 Tomcat 服务器上运行 Java Spring Boot 应用程序?
TL;DR:How does the Maven dependency parameter <scope>provided</scope>
affect running a Java Spring Boot application locally vs remotely on a Tomcat server?
推荐答案
provided
作用域表示不用担心,这些类会在运行时存在,因此无需将它们包含在战争.
The provided
scope says that don't worry, these classes will exist at runtime, so there's no need to include them in the WAR.
在完整的 tomcat 服务器中运行,您可以使用 provided
,因为存在类(不在 WAR 中).但是在本地使用嵌入式 tomcat 运行,它会失败,因为您说不要担心 tomcat 类.
Running in a full blown tomcat server, you can use provided
since the classes (not in the WAR) are present. However running locally with embedded tomcat, it will fail because you said not to worry about the tomcat classes.
这意味着您不能对开发和生产使用相同的范围.您可以创建使用不同范围的不同 Maven 配置文件,并且使用开发"配置文件进行本地开发.
This means that you can't use the same scope for both dev and production. You could create different Maven profiles that use a different scope, and use a "dev" profile for local development.
然后就像在进行本地开发时添加 -Pdev
一样简单.
Then it's as easy as adding a -Pdev
whenever you're doing local development.
这篇关于Java Spring Boot - spring-boot-starter-tomcat 依赖项不适用于本地运行时提供的范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!