2013-03-14 6 views
0

Я хочу использовать пружинные управляемые бобы для своих контроллеров JSF2, чтобы работа автомашины работала. Я знаю, что весной нет @ViewScoped, и я знаю несколько реализаций @ViewScoped, плывущих вокруг разных блогов (один из строк).Spring/JSF2 и @ViewScoped

Является ли какой-либо из них использованным в реальном приложении и считается стабильным? Возможно, один из них рекомендуется или широко используется, и я просто не могу его найти.

ответ

1

Существует один: без утечек памяти и с поддержкой @PreDestroy. Протестировано в производстве. Here.

package org.nkey.primefaces.scopes.test.spring.scope; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.ObjectFactory; 
import org.springframework.beans.factory.config.Scope; 

import javax.faces.component.UIViewRoot; 
import javax.faces.context.FacesContext; 
import javax.faces.event.PreDestroyViewMapEvent; 
import javax.servlet.http.HttpSession; 
import javax.servlet.http.HttpSessionBindingEvent; 
import javax.servlet.http.HttpSessionBindingListener; 
import java.io.Serializable; 
import java.util.HashSet; 
import java.util.Map; 
import java.util.Set; 
import java.util.WeakHashMap; 

/** 
* @author m.nikolaev Date: 21.11.12 Time: 0:37 
*/ 
public class ViewScope implements Scope, Serializable, HttpSessionBindingListener { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ViewScope.class); 
    private final WeakHashMap<HttpSession, Set<ViewScopeViewMapListener>> sessionToListeners = new WeakHashMap<>(); 

    @Override 
    public Object get(String name, ObjectFactory objectFactory) { 
     Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
     //noinspection SynchronizationOnLocalVariableOrMethodParameter 
     synchronized (viewMap) { 
      if (viewMap.containsKey(name)) { 
       return viewMap.get(name); 
      } else { 
       LOGGER.debug("Creating bean {}", name); 
       Object object = objectFactory.getObject(); 
       viewMap.put(name, object); 

       return object; 
      } 
     } 
    } 

    @Override 
    public Object remove(String name) { 
     throw new UnsupportedOperationException(); 
    } 

    @Override 
    public String getConversationId() { 
     return null; 
    } 

    @Override 
    public void registerDestructionCallback(String name, Runnable callback) { 
     LOGGER.debug("registerDestructionCallback for bean {}", name); 
     UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot(); 
     ViewScopeViewMapListener listener = 
       new ViewScopeViewMapListener(viewRoot, name, callback, this); 

     viewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, listener); 

     HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true); 
     final Set<ViewScopeViewMapListener> sessionListeners; 
     synchronized (sessionToListeners) { 
      if (!sessionToListeners.containsKey(httpSession)) { 
       sessionToListeners.put(httpSession, new HashSet<ViewScopeViewMapListener>()); 
      } 
      sessionListeners = sessionToListeners.get(httpSession); 
     } 
     //noinspection SynchronizationOnLocalVariableOrMethodParameter 
     synchronized (sessionListeners) { 
      Set<ViewScopeViewMapListener> toRemove = new HashSet<>(); 
      for (ViewScopeViewMapListener viewMapListener : sessionListeners) { 
       if (viewMapListener.checkRoot()) { 
        toRemove.add(viewMapListener); 
       } 
      } 
      sessionListeners.removeAll(toRemove); 
      sessionListeners.add(listener); 
     } 
     if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey("sessionBindingListener")) { 
      FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionBindingListener", this); 
     } 

    } 

    @Override 
    public Object resolveContextualObject(String key) { 
     return null; 
    } 

    @Override 
    public void valueBound(HttpSessionBindingEvent event) { 
     LOGGER.debug("Session event bound {}", event.getName()); 
    } 

    @Override 
    public void valueUnbound(HttpSessionBindingEvent event) { 
     LOGGER.debug("Session event unbound {}", event.getName()); 
     final Set<ViewScopeViewMapListener> listeners; 
     synchronized (sessionToListeners) { 
      if (sessionToListeners.containsKey(event.getSession())) { 
       listeners = sessionToListeners.get(event.getSession()); 
       sessionToListeners.remove(event.getSession()); 
      } else { 
       listeners = null; 
      } 
     } 
     if (listeners != null) { 
      for (ViewScopeViewMapListener listener : listeners) { 
       listener.doCallback(); 
      } 
     } 
    } 

    public void clearFromListener(ViewScopeViewMapListener listener) { 
     LOGGER.debug("Removing listener from map"); 
     HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false); 
     if (httpSession != null) { 
      synchronized (sessionToListeners) { 
       if (sessionToListeners.containsKey(httpSession)) { 
        sessionToListeners.get(httpSession).remove(listener); 
       } 
      } 
     } 
    } 

} 
+0

Эта реализация действительно утешила огромный объем памяти в нашей среде. Объекты в 'sessionToListeners' никогда не были GCed. Не исследовали дальше, хотя нам не нужна поддержка '@ PreDestroy'. – atamanroman

+0

@atamanroman, проверьте последнюю версию здесь - https://github.com/michail-nikolaev/primefaces-spring-scopes, проверенные на реальном проекте, никаких утечек до сих пор –

Смежные вопросы