问题描述
我们正在逐步用Spring-MVC和Spring-Webflow替换Seam组件.
We are gradually replacing Seam components with Spring-MVC and Spring-Webflow.
运行JMeter-测试几个小时后,日志会出现StackOverFlowErrors混乱的情况:
Running JMeter-tests the logs get cluttered with StackOverFlowErrors after a couple of hours:
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.
So the getMessageBundle method is called by two instances: SeamApplication and FlowApplication.
查看javax.faces.application.Application类,它显示:
Looking at the javax.faces.application.Application class it says:
因为该实例是共享的,所以必须以线程安全的方式实现."
"Because this instance is shared, it must be implemented in a thread-safe manner."
也许这两个应用程序实例正在尝试访问导致竞争情况的同一个捆绑软件?
Maybe the two app instances are trying to access the same bundle which causes race conditions?
应用不再响应后,我们重新启动了服务器,现在错误显示在另一个位置:
After the app did not respond anymore we restarted the server and now the error shows up in another place:
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)
最后两行在日志文件中重复了数千次.
The last 2 lines are repeated thousands of times in the log file.
我们正在处理以下组件版本:
We are working with the following component-versions:
JSF-1.2
Seam-2.2.0
Seam-2.2.0
Spring WebFlow 2.3.4
Spring WebFlow 2.3.4
Spring MVC 3.0.5
Spring MVC 3.0.5
不能更新任何组件.
推荐答案
SeamApplication
和 FlowApplication
具有一些错误,无法正确委派给包装的应用程序.解决此问题的一种方法是通过 FlowApplicationFactory
.
首先获取其原始源代码并将其拖放到webapp项目的Java源文件夹中,并保持其原始包.您不一定需要操纵JAR. /WEB-INF/classes
中的类具有比JAR中的类更高的类加载优先级.
First grab its raw source code and drop it in the Java source folder of your webapp project, maintaining its original package. You don't necessarily need to manipulate JARs. Classes in /WEB-INF/classes
have higher classloading precedence over those in JARs.
然后按以下方式操作该类(基于 OmniFaces OmniApplicationFactory
):
Then manipulate the class as follows (based off from 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
时,它将首先检查已包装的应用程序(如果之前尚未创建),如果已创建,则将其重新使用.
Thus, when creating FlowApplication
, it will first inspect the wrapped applications if it isn't already created before and if so, then reuse it instead.
请注意,SeamApplication
依赖项很尴尬,但这只是为了对其进行错误修复.通过新的 ApplicationWrapper
类,您可以使用它代替createFlowApplication()
块中的SeamApplication
.
<factory>
<application-factory>org.jboss.seam.jsf.SeamApplicationFactory</application-factory>
<application-factory>org.springframework.faces.webflow.FlowApplicationFactory</application-factory>
</factory>
否则,您可能想要对 SeamApplicationFactory
(显然,在代码).
Otherwise, you might want to do the same as above for SeamApplicationFactory
(obviously with FlowApplication
and SeamApplication
swapped in the code).
这篇关于Seam/Spring WebFlow应用程序中的StackOverflowError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!