首页 > 解决方案 > tomcat config 导致 2 个 @Service 副本运行

问题描述

我有一个ScheduledExecutor运行在@PostConstruct我的一些@Service. 但是,这个 tomcat 配置会导致 2 个副本@Service运行,删除任何一个都会导致@Controllerin the wars 无法正常工作。

如何解决这个问题?我需要@Service成为单身人士,以便只有一个Executor运行一些代码。

设置Executortostatic只会使它成为一个Executor,但是有没有办法在配置级别实现这一点?

web.xml

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<servlet>
  <servlet-name>servlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:servlet-context.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
  <async-supported>true</async-supported>
</servlet>

servlet-context.xml

<import resource="applicationContext.xml" />

应用程序上下文.xml

<bean id="properties" class="my.package.common.properties.MyPropertyPlaceholderConfigurer">
  <property name="locations">
    <list>
      <value>WEB-INF/classes/system.properties</value>
      <value>WEB-INF/classes/db.properties</value>
      <value>WEB-INF/classes/applicationContext.properties</value>
    </list>
  </property>
</bean>

<context:annotation-config />
<context:component-scan base-package="my.package" />

标签: javaspringtomcat

解决方案


该问题很可能与您的以下导入有关servlet-context.xml

<import resource="applicationContext.xml" />

可能在您的web.xml文件中包含以下 Web 应用程序上下文侦听器:

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在典型的 Spring MVC 应用程序中,此侦听器负责根据 Web 应用程序上下文参数中指示的 XML 文件中提供的信息初始化 Spring根应用contextConfigLocation程序上下文:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/classes/applicationContext.xml</param-value>
</context-param>

另一方面,您在配置 Spring 时启动了第二个子应用程序上下文DispatcherServlet

<servlet>
    <servlet-name>servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

在您的示例中,第二个上下文基于servlet-context.xml.

理解这两个上下文以这样一种方式相关非常重要,即根应用程序上下文中定义的所有 bean 都可以被与其关联的子上下文访问DispatcherServlet(反之则不然)。

这允许您为 bean 组织和提供正确的层次结构:例如,根应用程序上下文通常定义服务和公共组件和配置(数据库、安全性、异步支持、缓存等),而子上下文定义与 MVC 相关的 bean东西。

Spring 文档中很好地解释了这种上下文层次结构:

mvc spring 上下文层次结构

import正如您所说,当您在文件中包含以下内容时servlet-context.xml

<import resource="applicationContext.xml" />

您实际上是在复制根上下文中定义的所有内容。

要解决此问题,请从servlet-context.xml.

根据您的评论,您的所有控制器都报告了错误404。可能原因是删除applicationContext.xmlSpring 后无法找到任何Controllers: 请确保您也包含component-scanservlet-context.xml其中,指向定义控制器的包。其中servlet-context.xml包括:

<context:component-scan base-package="my.package.controllers" />`

以这种方式包含在servlet-context.xml您需要的任何其他 MVC 资源中(查看解析器等)。

理想情况下,applicationContext.xml只需要扫描服务、存储库和类似内容等组件。


推荐阅读