Seam / Spring WebFlow应用程序中的StackOverflowError
问题内容:
我们正在逐步用Spring-MVC和Spring-Webflow替换Seam组件。
几个小时后,运行JMeter-tests日志会出现StackOverFlowErrors混乱的情况:
javax.servlet.ServletException: Servlet execution threw an exception
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:341)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:530)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
...
Caused by: java.lang.StackOverflowError
at org.jboss.seam.jsf.SeamApplication.getMessageBundle(SeamApplication.java:264)
at org.springframework.faces.webflow.FlowApplication.getMessageBundle(FlowApplication.java:214)
at org.jboss.seam.jsf.SeamApplication.getMessageBundle(SeamApplication.java:264)
at org.springframework.faces.webflow.FlowApplication.getMessageBundle(FlowApplication.java:214)
at org.jboss.seam.jsf.SeamApplication.getMessageBundle(SeamApplication.java:264)
at org.springframework.faces.webflow.FlowApplication.getMessageBundle(FlowApplication.java:214)
at org.jboss.seam.jsf.SeamApplication.getMessageBundle(SeamApplication.java:264)
因此,getMessageBundle方法由两个实例调用:SeamApplication和FlowApplication。
查看javax.faces.application.Application类,它说:
“因为该实例是共享的,所以必须以线程安全的方式实现。”
也许这两个应用程序实例正在尝试访问导致竞争情况的同一个捆绑软件?
编辑:应用程序不再响应后,我们重新启动了服务器,现在错误显示在另一个位置:
Caused by: java.lang.StackOverflowError
at org.jboss.seam.contexts.BasicContext.get(BasicContext.java:49)
at org.jboss.seam.contexts.BasicContext.get(BasicContext.java:44)
at org.jboss.seam.core.Init.instance(Init.java:117)
at org.jboss.seam.jsf.SeamApplication$ConverterLocator.<init>(SeamApplication.java:140)
at org.jboss.seam.jsf.SeamApplication.createConverter(SeamApplication.java:122)
at org.springframework.faces.webflow.FlowApplication.createConverter(FlowApplication.java:161)
at org.jboss.seam.jsf.SeamApplication.createConverter(SeamApplication.java:126)
at org.springframework.faces.webflow.FlowApplication.createConverter(FlowApplication.java:161)
at org.jboss.seam.jsf.SeamApplication.createConverter(SeamApplication.java:126)
最后两行在日志文件中重复数千次。
我们正在处理以下组件版本:
JSF-1.2
接缝2.2.0
Spring WebFlow 2.3.4
Spring MVC 3.0.5
无法更新任何组件。
问题答案:
无论是SeamApplication
和FlowApplication
有缺陷的正确委派到包装中的应用。解决它的一种方法是通过FlowApplicationFactory
。
首先,获取其原始源代码并将其放入webapp项目的Java源文件夹中,并保持其原始包。您不一定需要操纵JAR。中的类的/WEB- INF/classes
加载优先级高于JAR中的类。
然后按如下方式操作该类(基于OmniFaces
OmniApplicationFactory
):
public class FlowApplicationFactory extends ApplicationFactory {
private final ApplicationFactory wrapped;
private volatile Application application;
public FlowApplicationFactory(ApplicationFactory wrapped) {
this.wrapped = wrapped;
}
@Override
public Application getApplication() {
return (application == null) ? createFlowApplication(wrapped.getApplication()) : application;
}
@Override
public synchronized void setApplication(Application application) {
wrapped.setApplication(createFlowApplication(application));
}
private Application createFlowApplication(final Application application) {
Application newApplication = application;
while (!(newApplication instanceof FlowApplication) && newApplication instanceof SeamApplication) {
newApplication = ((SeamApplication) application).getDelegate();
}
if (!(newApplication instanceof FlowApplication)) {
newApplication = new FlowApplication(application);
}
return (this.application = newApplication);
}
}
因此,在创建时FlowApplication
,它将首先检查已包装的应用程序,如果之前尚未创建,则将其重新使用。
请注意,该SeamApplication
依赖项很尴尬,但这只是为了修正它。JSF2通过新ApplicationWrapper
类使您变得更轻松,您可以使用它而不是SeamApplication
在createFlowApplication()
块中使用。
如果这一切仍然无法正常工作,那么也许SeamApplicationFactory
初始化 后
的FlowApplicationFactory
。您可以通过按期望的顺序显式地重新声明<application- factory>
webapp自身faces-config.xml
中的条目来强制排序(错误修正为最后一个):
<factory>
<application-factory>org.jboss.seam.jsf.SeamApplicationFactory</application-factory>
<application-factory>org.springframework.faces.webflow.FlowApplicationFactory</application-factory>
</factory>
否则,您可能想要执行与上述相同的操作SeamApplicationFactory
(显然是在代码中FlowApplication
与SeamApplication
交换)。