StackruError в приложении Seam / Spring WebFlow
Мы постепенно заменяем компоненты Seam на Spring-MVC и Spring-Webflow.
При запуске 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.StackruError
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.StackruError
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
Шов-2.2.0
Spring WebFlow 2.3.4
Spring MVC 3.0.5
Обновление любого из компонентов не вариант.
1 ответ
Оба SeamApplication
а также FlowApplication
есть ошибки в отношении правильного делегирования в оболочку приложения. Один из способов исправить это через FlowApplicationFactory
,
Сначала возьмите его исходный код и поместите его в исходную папку 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>
записи в собственном веб-приложении 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
поменялся местами в коде).