Memory leak with ViewScoped bean?

≡放荡痞女 提交于 2019-11-27 21:38:45

I see many developers are satisfied with @ViewAccessScoped in Myface CODI. Could you please give it a try and tell the feedback.

I have faced the above mentioned problem in JSF managed @ViewScoped bean. After referring to few blogs I understood that JSF saves view bean states in http session and gets destroyed only when session is invalidated. Whenever we click on the jsf page every time new view scope bean referred in page is created. I did a work around using Spring Custom View Scope. It works fine. Below is the detail code.

For JSF 2.1:

Step 1: Create a View Scope Bean Post Construct Listener as follows.

    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());
            }
        }
    }

Step 2: Register event listener in 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>

Step 3: Create a Custom View Scope bean as follows.

 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;
           }

    }

Note : Other overridden methods can be empty.

For JSF 2.2:

JSF 2.2 saves the navigated view maps in http session in 'com.Sun.faces.application.view.activeViewMaps' as key. So add the below code in Spring Custom View Scope. No need of listeners as in 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;
        }
 }

Chances are this is a bug. Honestly the Seam 3 implementation wasn't all that great and the CODI one (and also what will be in DeltaSpike) is much better.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!