【问题标题】:StackoverflowExcepton in Spring message i18n ReloadableResourceBundleMessageSourceSpring消息i18n ReloadableResourceBundleMessageSource中的StackoverflowExcepton
【发布时间】:2017-10-26 05:20:34
【问题描述】:

我正在我的 Spring Web 应用程序中启用消息 i18n。为此,我的servlet.xml中有以下代码

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages/message"/>
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>

添加上述代码后,只要我在浏览器中点击我的应用程序,就会出现以下异常日志:

SEVERE: Servlet.service() for servlet [default] in context with path [/ERP-Web] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError
    at org.springframework.context.support.ReloadableResourceBundleMessageSource.getMergedProperties(ReloadableResourceBundleMessageSource.java:235)
    at org.springframework.context.support.ReloadableResourceBundleMessageSource.resolveCodeWithoutArguments(ReloadableResourceBundleMessageSource.java:176)
    at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:209)
    at org.springframework.context.support.AbstractMessageSource.getMessageFromParent(AbstractMessageSource.java:257)

最后两行重复了 100 次并给了我StackoverflowException

当我使用ResourceBundleMessageSource 类时,会出现完全相同的异常。

我的春季版是4.3.6.RELEASE

以下是我的属性文件的内容

action.add.success = New {0} added successfully.
action.add.failure = Some error occurred in adding new {0}. Please try again later or contact administrator.

示例项目位于GitHub

【问题讨论】:

  • 添加您的消息属性文件,在我的情况下,无论有无类路径都可以正常工作
  • 它加载了属性文件,但是当我从浏览器中点击我的应用程序时,我就出现了异常。
  • 很奇怪。您是否有一个迷你项目来重现错误以便可以对其进行调查?
  • 呃……会尝试给你一个迷你项目。不过可能需要一两天。为这个延迟表示歉意
  • 添加了示例项目@TestoTestini

标签: java spring maven spring-mvc internationalization


【解决方案1】:

您应该使用ResourceBundleMessageSource 的方式是在basename 属性上设置消息文件的路径。

例如,如果您有两个消息文件:

  • messages_en.properties
  • messages_es.properties

位于resources 文件夹。你的 bean 配置应该是这样的:

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
  <property name="basename" value="messages" />
</bean>

其中messages 是两个文件名的前缀。

也许Exception 被抛出是因为 Spring id 试图自动加载类路径,而你也包含了它,所以它会一次又一次地尝试加载它...

您可以在 Mkyong's 上找到一个工作示例。

【讨论】:

  • 除非我在值中使用 classpath:,否则我的应用程序不会加载文件。无论是否加载文件都会抛出上述异常。
【解决方案2】:

这在我的applicationContext.xml 文件中对我有用:

<bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:i18n/message" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>

<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="lang" />
</bean>

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="en"/>
</bean>

<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
        <ref bean="localeChangeInterceptor" />
    </property>
</bean>

请注意,我将属性文件放在以下路径中:

src/main/resources/i18n/message_en.properties

【讨论】:

    【解决方案3】:

    更新

    就我运行您的演示项目而言:

    • 删除default-autowire="byType",这会将消息源的父级设置为自身,这会导致stackoverflow;
    • 避免LocaleContextHolder.getLocale(),它在系统默认区域设置上中继;
    • 使用正确的基本名称,这对于ReloadableResourceBundleMessageSourceResourceBundleMessageSource 是不同的,可以解决以下警告;

      找不到 MessageSource 的 ResourceBundle [消息/消息]:找不到基本名称消息/消息的包,语言环境 en_US

    Runnable example


    堆栈跟踪

    据我从您的堆栈跟踪中可以看出,您可能遇到三个问题:

    • 您不提供参数,但您的财产需要它;
    • 您拥有的消息源与其父级具有循环依赖关系,这导致StackOverflow(因为AbstractMessageSource 具有类加载器之类的模型,即如果无法解析则委托给父级);
    • 我不确定你的属性是否真的被消息源找到,如果找到了,即使是循环依赖也不会StackOverflow;

    建议

    • 至于为什么存在循环依赖,根据目前的信息,我无法判断是spring的bug还是配置错误;
    • 如果不方便提供示例项目,可以试试4.1.6 Relase,我试过了,效果很好;
    • 你可以设置日志级别为DEBUG或者设置断点,看看你的属性文件是否真的加载了;

    【讨论】:

    • 添加了示例项目。这似乎是您所说的第二个可能的问题。虽然尚未确定这是我的代码中的问题还是 Spring 库中的错误。虽然后者不太可能。
    • 我不能降级 spring 版本,很多开发已经完成,它会导致级联事件,我需要降级 Hibernate 版本并重新编码我的 DAO 层。
    • 啊...你建议我尝试4.1.6. Release,而我正在使用4.3.6 Release。这就是为什么我之前的评论
    • @Aakash 所以现在有什么问题吗?
    • 当我使用Spring 自动装配时,无法删除default-autowire="byType"。这是必需的属性,否则我的应用程序将无法运行。
    【解决方案4】:

    非常奇怪的情况;-)

    根本问题是messageSource 自动连接到自身(在parentMessageSource 属性中),因为您使用default-autowire="byType" 这会导致未知消息代码的stackoverflow 异常,从而搞砸一切。必须说 logback 给混乱添乱了,因为有时似乎异常发生在其代码中,Log4J 处理得更好。

    Autowiring is not good for big projects,你的情况是一个经典案例,但是如果你必须使用它,请更改 messageSource bean 添加以下内容:

           <property name="parentMessageSource"><null/></property>
    

    通过这种方式,您将自己连接到父级并且不会发生自动连接。

    这将恢复正常情况,即使用NoSuchMessageException 报告未找到的消息

    然后:

    1. 在控制器中,您必须请求hello.world 消息,而不是message
    2. 您缺少默认资源,即代表默认语言环境或您的应用程序的无语言环境后缀文件。在您的情况下是messages/message.properties 简单来说,您的应用程序的默认语言环境是您拥有所有消息的语言环境。从那开始,然后添加新的语言(可能不完整)。

    【讨论】:

      【解决方案5】:

      我已经在github中测试了你的示例代码,运行时出现了描述的错误,然后修改如下:

      配置:

      <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
              <property name="basename" value="messages/message"/>
              <property name="defaultEncoding" value="UTF-8"/>
      </bean>
      

      类:

      @RequestMapping(method=RequestMethod.GET)
      @ResponseBody
      public String getMessage() {
          String msg = messageSource.getMessage("hello.world", null, LocaleContextHolder.getLocale());
          return msg;
      }
      

      hello.word 是文件中名称为 message_en.properties 的带有文本的属性。

      通过这些修改,代码运行。

      编辑未知消息代码:

      我尝试了未知的消息代码,错误重复,所以我查看注册表,发现可能有多个同名的bean(潜在的循环引用),但我还没有发现为什么会发生这种情况,但是如果你需要工作,你必须像这样重命名 bean。

      <bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
              <property name="basename" value="messages/message"/>
              <property name="defaultEncoding" value="UTF-8"/>
          </bean>
      

      然后使用:

      @Autowired
      private MessageSource myMessageSource;
      

      但我认为这并不能解决循环潜在错误的主要问题。

      【讨论】:

      • 是的,但他仍然会收到未知消息代码的 stackoverflow 异常
      猜你喜欢
      • 2012-02-20
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 2016-03-27
      • 2013-11-18
      • 2011-08-17
      • 1970-01-01
      • 2012-10-08
      相关资源
      最近更新 更多