在Payara(Hazelcast)上激活HA后,我注意到日志中有以下WARN消息:
[2017-12-12T15:12:31.266+0800] [Payara 4.1] [WARNING] [] [javax.enterprise.web.core] [tid: _ThreadID=63 _ThreadName=http-thread-pool::http-listener-2(2)] [timeMillis: 1513062751266] [levelValue: 900] [[
StandardSession: Cannot serialize session attribute com.sun.faces.application.view.activeViewMaps for session 9914fe69fd67044327585dc07409]]
深入研究这个问题,我最终得到了@ViewScope
地图中包含的sessionScope['com.sun.faces.application.view.activeViewMaps']
bean的手动序列化按钮,以找到导致此问题的bean。
事实证明,问题是由@EJB
bean中@ViewScoped
的使用引起的。这里有几篇文章讨论了这个问题,但似乎没有人为集群环境提供解决方案。
所以基本上有一个主要问题:如何在集群环境中的JSF @EJB
CDI bean中正确使用@VeiwScoped
(SLSB)?
我看到的一种可能的解决方案 - 就像这样: https://stackoverflow.com/a/10145618/2261312
上面提到的解决方案的想法 - 只是将ViewScoped
bean拆分为两个bean:@ViewScoped
与实际的视图相关逻辑,EJB bean移动到单独的@RequestScoped
bean,并将@RequestScoped
bean注入@ViewScoped
bean,以便访问@EJB
个服务。
但从代码语法/设计的角度来看,这看起来很奇怪......这里还有其他建议吗?
谢谢!
二手软件:JSF 2.3.3(Mojarra),Payara Server 4.1.2.174(完整版),基于Hazelcast的集群
到目前为止我找到的链接:
更新1:
我做了几个额外的测试并且发现,即使WARN消息StandardSession: Cannot serialize session attribute com.sun.faces.application.view.activeViewMaps for session ...
出现在日志中,集群也能正常工作,最终用户可以在集群节点之间切换,而不会出现任何问题。 JSF应用程序中的ViewScoped CDI Bean:注入@EJB
的SLSB即使在故障转移到其他群集节点后仍然有效。
因此,基本上现在的问题是:如果忽略此WARN消息,或者无论如何必须解决它?
关于测试用例场景的几句话:
1)部署包括三台服务器:
2)JSF应用程序:
2.1)JSF查看:
<ui:composition>
<ui:define name="content">
<h:form id="ft1">
mark2 = #{testBean.mark2}<br/>
mark3 = #{testBean.mark3}<br/>
<p:commandButton value="TEST SER" action="#{testBean.test1()}" /><br/>
<p:commandButton value="TEST2" action="#{testBean.test2()}" update="@form"/>
</h:form>
</ui:define>
</ui:composition>
2.2)JSF ViewScope Bean:
package ua.local.beans;
import ....
import javax.faces.view.ViewScoped;
import ....
@Named
@ViewScoped
public class TestBean implements Serializable {
private static final long serialVersionUID = -4596312102341014148L;
@EJB
private LogDao _logDao;
private long mark2 = 0;
private long mark3 = 0;
public void test1() {
try {
File serFile = File.createTempFile("debug_", ".ser");
FileOutputStream fileOut = new FileOutputStream(serFile);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(this);
out.close();
fileOut.close();
System.out.printf("TEST: Serialized data is saved in " + serFile.getAbsolutePath());
} catch (Exception i) {
i.printStackTrace();
}
}
public void test2() {
System.out.println(">> found LOGS: " + _logDao.findAll().size());
mark2 = mark3;
mark3 = System.currentTimeMillis();
}
public long getMark2() {
return mark2;
}
public long getMark3() {
return mark3;
}
}
2.3)SLSB:
@Stateless
public class LogDaoMongoImpl extends AbstractMongoDAO<Log> implements LogDao, Serializable {
...
}
即使有WARN消息,这在集群环境中也能正常工作。