在在JBoss 7.1.1我们JavaEE6项目(EJB3,JSF2),看来我们有SeamFaces内存泄漏@ViewScoped
。
我们做了一个小的原型检查的事实:
- 我们使用JMeter的调用页面200次;
- 该页面包含并调用viewscoped Bean上注入一个有状态EJB;
- 我们修复会话超时1分钟。
在测试结束后,我们检查与VisualVM的存储器的内容,在这里我们得到了什么:
- 用
@ViewScoped
豆,我们还是得到了状态的200个实例MyController
-和@PreDestroy
方法不会被调用; - 用
@ConversationScoped
豆, @preDestroy
方法被称为会话结束,然后我们得到了一个干净的内存。
难道我们不好使用的视图范围,还是真正的错误吗?
这里的XHTML页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:s="http://jboss.org/seam/faces">
<f:metadata>
<f:viewParam name="u" value="#{myBean.uselessParam}" />
<s:viewAction action="#{myBean.callService}" />
</f:metadata>
<h:body >
<f:view>
</f:view>
</h:body>
</html>
现在,包括豆myBean
。 对于@ConversationScoped
变型,所有的评论部分是注释。
@ViewScoped
// @ConversationScoped
@Named
public class MyBean implements Serializable
{
@Inject
MyController myController;
//@Inject
//Conversation conversation;
private String uselessParam;
public void callService()
{
//if(conversation.isTransient())
//{
// conversation.begin();
//}
myController.call();
}
public String getUselessParam()
{
return uselessParam;
}
public void setUselessParam(String uselessParam)
{
this.uselessParam = uselessParam;
}
}
然后注入的状态bean MyController
:
@Stateful
@LocalBean
public class MyController
{
public void call()
{
System.out.println("call ");
}
@PreDestroy
public void destroy()
{
System.out.println("Destroy");
}
}
我看到很多开发商都感到满意Myface CODI @ViewAccessScoped。 能否请你给它一个尝试,并告诉反馈。
我所面临的JSF上述问题管理@ViewScoped豆。 指的是一些博客后,我明白,JSF在HTTP会话中保存视图bean的状态,当会话失效,仅得到破坏。 每当我们点击JSF页面上页提到,每次新的视图范围内的bean创建。 我做了周围使用Spring自定义视图范围工作。 它工作正常。 下面是详细代码。
对于JSF 2.1:
第1步:创建视图范围bean后建设监听如下。
public class ViewScopeBeanConstructListener implements ViewMapListener {
@SuppressWarnings("unchecked")
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if (event instanceof PostConstructViewMapEvent) {
PostConstructViewMapEvent viewMapEvent = (PostConstructViewMapEvent) event;
UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent();
List<Map<String, Object>> activeViews = (List<Map<String, Object>>)
FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). get("com.org.jsf.activeViewMaps");
if (activeViews == null) {
activeViews = new ArrayList<Map<String, Object>>();
activeViews.add(viewRoot.getViewMap());
FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). put("com.org.jsf.activeViewMaps", activeViews);
} else {
activeViews.add(viewRoot.getViewMap());
}
}
}
第2步:注册在事件监听器faces-config.xml中
<system-event-listener>
<system-event-listener-class>
com.org.framework.custom.scope.ViewScopeBeanConstructListener
</system-event-listener-class>
<system-event-class>javax.faces.event.PostConstructViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
第3步:创建自定义视图范围豆如下。
public class ViewScope implements Scope {
@Override
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
List<Map<String, Object>> activeViewMaps = (List<Map<String, Object>>)
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("com.org.jsf.activeViewMaps");
if (activeViewMaps != null && !activeViewMaps.isEmpty()
&& activeViewMaps.size() > 1) {
Iterator iterator = activeViewMaps.iterator();
if (iterator.hasNext()) {
Map<String, Object> oldViewMap = (Map<String, Object>)
iterator.next();
oldViewMap.clear();
iterator.remove();
}
}
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
注:其他替代的方法可以是空的。
对于JSF 2.2:
JSF 2.2保存在HTTP会话中导航查看地图在“com.Sun.faces.application.view.activeViewMaps”为重点。 因此,在春天自定义视图范围添加下面的代码。 无需听众在JSF 2.1
public class ViewScope implements Scope {
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap =
FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
LRUMap lruMap = (LRUMap) FacesContext.getCurrentInstance().
getExternalContext().getSessionMap().get("com.sun.faces.application.view.activeViewMaps");
if (lruMap != null && !lruMap.isEmpty() && lruMap.size() > 1) {
Iterator itr = lruMap.entrySet().iterator();
while (itr.hasNext()) {//Not req
Entry entry = (Entry) itr.next();
Map<String, Object> map = (Map<String, Object>) entry.getValue();
map.clear();
itr.remove();
break;
}
}
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
可能这是一个错误。 说实话,缝3实施是不是所有的伟大和CODI一个(也将在DeltaSpike什么)要好得多。