我们正在逐步用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

无法更新任何组件。

最佳答案

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依赖项很尴尬,但这只是为了修正它。通过新的ApplicationWrapper类,您可以使用JSF2来简化它,您可以使用它代替SeamApplication块中的createFlowApplication()

如果这一切仍然不起作用,则可能在SeamApplicationFactory之后初始化FlowApplicationFactory。您可以通过按所需顺序在Webapp自己的<application-factory>中显式重新声明faces-config.xml条目来强制排序(错误修正为最后一个):

<factory>
    <application-factory>org.jboss.seam.jsf.SeamApplicationFactory</application-factory>
    <application-factory>org.springframework.faces.webflow.FlowApplicationFactory</application-factory>
</factory>


否则,您可能想要对SeamApplicationFactory进行上述操作(显然在代码中交换了FlowApplicationSeamApplication)。

07-26 03:52