Seam / Spring WebFlow应用程序中的StackOverflowError

时间:2014-08-15 16:51:58

标签: jsf spring-mvc seam spring-webflow

我们正在逐步用Spring-MVC和Spring-Webflow替换Seam组件。

运行JMeter测试几小时后,日志会被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类,它说:

“因为这个实例是共享的,所以它必须以线程安全的方式实现。”

也许这两个app实例正在尝试访问导致竞争条件的同一个捆绑包?

编辑: 在应用程序没有响应之后,我们重新启动了服务器,现在错误显示在另一个地方:

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)

最后2行在日志文件中重复数千次。

我们正在使用以下组件版本:

JSF-1.2

Seam-2.2.0

Spring WebFlow 2.3.4

Spring MVC 3.0.5

不能选择更新任何组件。

1 个答案:

答案 0 :(得分:1)

SeamApplicationFlowApplication都有正确委派给包装应用程序的错误。解决问题的一种方法是通过FlowApplicationFactory

首先获取它的raw source code并将其放在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可能会在<{strong> <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> 条目来强制执行排序(默认固定为最后一个):

FlowApplication

否则,您可能希望对SeamApplicationFactory做同样的事情(显然代码中交换了SeamApplication和{{1}}。)