Spring消息中的StackoverflowExcepton i18n ReloadableResourceBundleMessageSource

时间:2017-05-25 14:02:37

标签: java spring maven spring-mvc internationalization

我在我的Spring网络应用中启用了消息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)

最后2行重复了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

5 个答案:

答案 0 :(得分:1)

<强>更新

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

  • 删除default-autowire="byType",它会将您的消息来源的父级设置为自身,从而导致堆栈溢出;
  • 避免LocaleContextHolder.getLocale(),它在系统默认区域设置中继;
  • 使用正确的基本名称,ReloadableResourceBundleMessageSourceResourceBundleMessageSource可以解决以下警告;
      

    找不到MessageSource的ResourceBundle [messages / message]:无法找到基本名称消息/消息的包,locale en_US

<强> Runnable example

栈跟踪

就我从堆栈跟踪中看到的情况而言,您可能会遇到三个问题:

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

建议

  • 当谈到为什么存在循环依赖时,我无法根据当前信息判断它是弹簧错误还是错误配置;
  • 如果您不方便提供示例项目,可以尝试4.1.6 Relase,我尝试过,工作正常;
  • 您可以将日志级别设置为DEBUG或设置断点,以查看您的属性文件是否确实已加载;

答案 1 :(得分:1)

非常奇怪的情况; - )

基本问题是messageSource自动连接到自身(在parentMessageSource属性中)因为你使用default-autowire="byType"这会导致未知消息代码的堆栈溢出异常混乱一切。必须说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简单来说,应用程序的默认语言环境就是您拥有所有消息的语言环境。从那开始,然后添加新语言(可能不完整)。

答案 2 :(得分:1)

我已在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(潜在的循环引用< / strong>),但我没有发现为什么会发生这种情况,但是如果你需要工作,你必须像这样重命名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;

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

答案 3 :(得分:0)

您应该使用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找到一个有效的例子。

答案 4 :(得分:0)

这在我的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