【问题标题】:Application context being loaded twice - Spring Boot应用程序上下文被加载两次 - Spring Boot
【发布时间】:2014-08-18 03:55:17
【问题描述】:

我有一个相当简单的设置。一个包含 3 个模块的 maven 项目:core/webapp/model。我正在使用 Spring Boot 来加速我的应用程序。在 webapp 中,我有一个简单的类 WebappConfig 如下:

@Configuration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @ComponentScan.Filter(Configuration.class))
public class WebappConfig {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(WebappConfig.class);
        app.setAdditionalProfiles("dev");
        app.run(args);
    }
}

核心/模型模块中的类很少。我的容器应用点是:

public class AbcdXml extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebappConfig.class);
    }

}

而且没有 web.xml!我的模型的 pom 具有以下与 spring boot 相关的依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Core 的 pom.xml :

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
</dependency>
<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>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
</dependency>

现在通过运行方式运行 WebappConfig -> Java 应用程序运行良好,但我需要将该项目部署为对 tomcat7 的战争。 Webapp 的包装是战争。除了 tomcat-jdbc 和 tomcat-tuli jar 之外,lib 中没有 tomcat 提供的 jar(应该不是问题吗?)。

当我部署我的 abcd.war 时,applicationcontext 被加载两次并导致以下错误 stracktrace:

2014-06-27 11:06:08.445  INFO 23467 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/abcd]        : Initializing Spring embedded WebApplicationContext
2014-06-27 11:06:08.446  INFO 23467 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 19046 ms
2014-06-27 11:06:21.308  INFO 23467 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-06-27 11:06:21.313  INFO 23467 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'errorPageFilter' to: [/*]
2014-06-27 11:06:21.314  INFO 23467 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-06-27 11:06:26.073  INFO 23467 --- [ost-startStop-1] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2014-06-27 11:06:26.127  INFO 23467 --- [ost-startStop-1] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
2014-06-27 11:06:26.511  INFO 23467 --- [ost-startStop-1] org.hibernate.Version                    : HHH000412: Hibernate Core {4.3.1.Final}
2014-06-27 11:06:26.521  INFO 23467 --- [ost-startStop-1] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2014-06-27 11:06:26.527  INFO 23467 --- [ost-startStop-1] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
//some info messages from spring boot
2014-06-27 11:07:31.664  INFO 23467 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-27 11:07:33.095  INFO 23467 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-27 11:07:33.096  INFO 23467 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-27 11:07:36.080  INFO 23467 --- [ost-startStop-1] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-06-27 11:08:49.583  INFO 23467 --- [ost-startStop-1] o.s.boot.SpringApplication               : Started application in 183.152 seconds (JVM running for 210.258)
2014-06-27 11:12:29.229 ERROR 23467 --- [ost-startStop-1] o.a.c.c.C.[.[localhost].[/abcd]        : Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:277)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:976)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1653)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

没有我之前提到的 web.xml。

一些有趣的事情我不知道为什么:

  1. 引爆war后,tomcat莫名其妙地用默认web.xml创建了一个ROOT文件夹[一定是Spring boot配置错误。我该如何纠正?请指点?]
  2. 即使我在 AbcdXml.java 中返回相同的“应用程序”SpringApplicationBuilder,我仍面临应用程序上下文被加载两次的相同问题。

感谢您的帮助!

编辑 1:

ROOT文件夹中生成的web.xml内容:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" version="2.5">
</web-app>

【问题讨论】:

  • 神秘的 web.xml 包含什么?
  • ROOT文件夹中生成的那个?在问题中更新。
  • 这看起来无害。但是您在堆栈跟踪中有一个ContextLoaderListener,这似乎是错误的。也许你可以从一个单一的战争文件开始(放弃其他两个)并重现问题,然后发布整个项目的链接?
  • 嗯,模型打包是jar,核心是jar,模块之间的依赖是正常的。核心需要模块,webapp 需要核心。当您说“抛弃其他两个”时,也许我在这里遗漏了一些东西?反正有一场战争!
  • 只是想减少表面积。也许你的一个罐子里有一个WebApplicationInitilaizer

标签: spring tomcat spring-boot


【解决方案1】:

API 中的@EnableAutoConfiuguration 表示“启用 Spring 应用程序上下文的自动配置,尝试猜测和配置您可能需要的 bean。”

@ComponentScan 也会实例化 bean。 IT 将扫描包,查找并注册 bean。

当您同时使用这两个注释时,我想这就是它加载两次的原因。

【讨论】:

  • 我不这么认为!它们处于不同的上下文中。好吧,反正也没用。
【解决方案2】:

如果您的应用包含 jersey-spring3 并且您没有采取措施禁用,它会尝试为您创建一个 ApplicationContext(有帮助,但没有)。有一种方法可以将其关闭(在 WebApplicationInitializer 中):

servletContext.setInitParameter("contextConfigLocation", "<NONE>");

或者直接使用这个:https://github.com/dsyer/spring-boot-jersey(包含为依赖项)。

【讨论】:

    【解决方案3】:

    在我的例子中,罪魁祸首是使用 Spring Boot 1.3.0.M4 和 Jersey 2.21。当我将 Spring Boot 降级到 1.2.6.RELEASE 时,问题就消失了。 我唯一要做的就是显式覆盖以下属性,因为我需要 spring 4.2.0 来支持 Hibernate 5,而 jackson 2.6.2 来支持 JSR310 (java8 java.time):

    <spring.version>4.2.0.RELEASE</spring.version>
    <jackson.version>2.6.2</jackson.version>
    

    编辑:从 spring-boot 1.3.0.RELEASE 开始,这个错误仍然存​​在。见github

    【讨论】:

      【解决方案4】:

      就我而言 - 我遇到了同样的问题 - 两次看到 Spring splash screen - 这是因为我有 2 个类扩展了 SpringBootServletInitializer。一个叫SpringBootWebApplication,另一个叫ServletInitializer。我刚刚删除了ServletInitializer,它工作正常。不知道为什么有 2 个类 - 可能是因为我从 2 个不同的示例中得到启发来组装我需要的东西。

      【讨论】:

      • 这也是我的问题。
      • ServletInitializer.java 由 Spring Boot Starters 自动生成(例如在 STS 中创建新项目时)。这也吸引了我,它应该是一个有用的功能:/
      【解决方案5】:

      我的主要问题是我的 spring 上下文被加载了两次。当我打印每个类的类加载器时,我发现我的应用程序运行了两次。 (即,当我在按 F9 后在 intellij 中进行调试时,我再次登陆同一行,即

      ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigAssignServer.class, args);
      

      我的问题出在 pom.xml 中。我从我的 pom 中删除了以下依赖项,它起作用了。

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-devtools</artifactId>
          <scope>runtime</scope>
      </dependency>
      

      请检查您的依赖项。希望它会帮助某人。享受编码:)

      【讨论】:

        【解决方案6】:

        我遇到了同样的问题

        我有 src>main>webapp>WEB-INF>web.xml 有一个实体要说

        <listener>
        	<listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
        </listener>

        这是第二次加载我的上下文。

        注释掉它只会加载一次。

        【讨论】:

          【解决方案7】:

          我正在使用 Spring Boot 2.5.5 并遇到同样的问题,但没有错误 (WebApplicationContext) 被加载两次,同时调度程序调用也被触发。

          在调试我的应用程序和服务器(Tomcat v9.0.53)设置后,我自己可以通过删除 Spring 初始化程序项目中的“ServletInitializer.java”类来解决问题。

          现在,所有已解决的问题(如调度程序)都会在预定义的时间与上下文加载一起调用一次。

          希望这能解决问题。

          【讨论】:

            猜你喜欢
            • 2012-10-04
            • 2019-06-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-30
            • 2015-02-19
            相关资源
            最近更新 更多