【问题标题】:JSF View scope in SpringSpring中的JSF视图范围
【发布时间】:2012-10-11 21:47:35
【问题描述】:

Spring 3.0 中是否有类似 JSF @ViewScoped 的范围?我有一个使用 JSF+Spring 的应用程序,其中支持 bean 由 Spring 管理。我在 Spring 中没有找到像 JSF wiew 范围这样的范围。我看到了博客Porting JSF 2.0’s ViewScope to Spring 3.0,但它对我不起作用。

这是我对自定义 Spring 范围的尝试:

import java.util.Map;

import javax.faces.context.FacesContext;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

/**
 * Implements the JSF View Scope for use by Spring. This class is registered as a Spring bean with the CustomScopeConfigurer.
*/
public class ViewScope implements Scope {

    public Object get(String name, ObjectFactory<?> objectFactory) {

        System.out.println("**************************************************");
        System.out.println("-------------------- Getting objects For View Scope ----------");
        System.out.println("**************************************************");
        if (FacesContext.getCurrentInstance().getViewRoot() != null) {
            Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
            if (viewMap.containsKey(name)) {
                return viewMap.get(name);
            } else {
                Object object = objectFactory.getObject();
                viewMap.put(name, object);
                return object;
            }
        } else {
            return null;
        }
    }

    public Object remove(String name) {
        System.out.println("**************************************************");
        System.out.println("-------------------- View Scope object Removed ----------");
        System.out.println("**************************************************");

        if (FacesContext.getCurrentInstance().getViewRoot() != null) {
            return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
        } else {
            return null;
        }
    }

    public void registerDestructionCallback(String name, Runnable callback) {
        // Do nothing
    }

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

    public String getConversationId() {
        return null;
    }

}

application-context.xml:

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
            <map>
                <entry key="view">
                    <bean class="com.delta.beans.ViewScope"/>
                </entry>
            </map>
        </property>
 </bean>

【问题讨论】:

  • 我的这篇文章可能会有所帮助:stackoverflow.com/q/12884822/1055089
  • 是的,但是在我的代码中实现不工作
  • 能否请您发布代码?我在我的应用程序中使用了相同的方法并且它有效。我也在使用 JSF2 + Spring 3...
  • 是的,我正在使用相同的 JSF2 + Spring 3 ...我已经粘贴了 ..
  • 你能详细说明什么不起作用吗?只是为了确保您的代码可以与 @Scope("request") 一起使用?

标签: spring jsf jsf-2 view-scope


【解决方案1】:

最近我创建了 maven artifact 来解决这个问题。

查看我的 github javaplugs/spring-jsf 存储库。

【讨论】:

    【解决方案2】:

    我在没有将 bean 移植到 Spring 的情况下做了类似的事情。它对我有用。

    @ManagedBean(name="bean")
    @ViewScoped  // actual jsf viewscoped only with javax.faces.viewscoped import
    public class Bean implements
    Serializable {
    
    
    @ManagedProperty(value="#{appService}")   // Spring Manged Bean and singleton
    private transient AppService appService;
    
      // Getting AppService Object which is singleton in the application during deserialization 
     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
              stream.defaultReadObject();
              FacesContext context = FacesContext.getCurrentInstance();
              appService = (AppService)context.getApplication()
                    .evaluateExpressionGet(context, "#{appService}", AppService.class);
           }
    }
    

    【讨论】:

    • 这是一个纯 JSF 解决方案。它工作正常,但缺少 Spring 的功能。例如,它不允许面向方面的编程。
    • 我不太确定Spring AOP。因为我当时根据我的要求测试了这个。但我有 Spring core 非常适合我。
    • 啊,我明白了。您很可能通过将 SpringBeanFacesELResolver 添加到 faces.config 将 JSF 解决方案转换为 Spring 解决方案。如果是这样,AOP 应该可以正常工作。
    • 尽管如此,它并不是一个完整的视图范围的 Spring bean。您自己评论了:Bean 类是视图范围的,但它使用的 spring bean 属于不同的范围。根据评论,它是一个单例,你称它为服务,所以它可能是无状态的。大多数开发人员都对您的解决方案感到满意。但不一样:Spring bean 不能存储特定于视图的状态。
    • 我不确定它在哪里存储与视图相关的状态。我只是得到在序列化时变为空的spring bean,因为它被标记为瞬态,因为@viewscope希望所有依赖bean都是Serialized。还有一件事Singletons 不是无状态的。
    【解决方案3】:
    public class ViewScopeCallbackRegistrer 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();
    
          viewRoot.getViewMap().put(
              ViewScope.VIEW_SCOPE_CALLBACKS,
              new HashMap<String, Runnable>()
          );
    
        } else if (event instanceof PreDestroyViewMapEvent) {
          PreDestroyViewMapEvent viewMapEvent = (PreDestroyViewMapEvent) event;
    
          UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent();
    
          Map<String, Runnable> callbacks = (Map<String, Runnable>) viewRoot
              .getViewMap().get(ViewScope.VIEW_SCOPE_CALLBACKS);
    
          if (callbacks != null) {
            for (Runnable c : callbacks.values()) {
              c.run();
            }
            callbacks.clear();
          }
        }
      }
    
      @Override
      public boolean isListenerForSource(Object source) {
        return source instanceof UIViewRoot;
      }
    }
    

    【讨论】:

      【解决方案4】:
      public class ViewScope implements Scope {
      
      public static final String VIEW_SCOPE_CALLBACKS = "viewScope.callbacks";
      
      @Override
      public synchronized Object get(String name, ObjectFactory<?> objectFactory) {
      Object instance = this.getViewMap().get(name);
      if(instance == null){
      instance = objectFactory.getObject();
      this.getViewMap().put(name, instance);
      }
      return instance;
      }
      
      @SuppressWarnings("unchecked")
      @Override
      public Object remove(String name) {
      Object instance = this.getViewMap().remove(name);
      if(instance == null){
      Map<String, Runnable> callbacks = (Map<String, Runnable>) this.getViewMap().get(VIEW_SCOPE_CALLBACKS);
      if(callbacks != null)
      callbacks.remove(name);
      }
      return instance;
      }
      
      /**
      * Responsável por registrar uma chamada de destruição ao bean
      * que será armazenadano [b]viewMap[/b] da [b]ViewRoot[/b](nossa página que será mostrada)
      * @see #getViewMap()
      * @param name - nome do bean
      * @param runnable
      */  
      @SuppressWarnings("unchecked")
      @Override
      public void registerDestructionCallback(String name, Runnable runnable) {
      Map<String, Runnable> callbacks = (Map<String, Runnable>) this.getViewMap().get(VIEW_SCOPE_CALLBACKS);
      if(callbacks != null)
      callbacks.put(name, runnable);
      }
      
      @Override
      public Object resolveContextualObject(String key) {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      FacesRequestAttributes facesResquestAttributes = new FacesRequestAttributes(facesContext);
      return facesResquestAttributes.resolveReference(key);
      }
      
      @Override
      public String getConversationId() {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      FacesRequestAttributes facesResquestAttributes = new FacesRequestAttributes(facesContext);  
      return facesResquestAttributes.getSessionId() + "-" + facesContext.getViewRoot().getViewId();
      }
      
      private Map<String, Object> getViewMap(){
      return FacesContext.getCurrentInstance().getViewRoot().getViewMap();
      }
      
      }
      

      【讨论】:

        【解决方案5】:

        我已尝试解决 Jsf 2.1 和 Jsf 2.2 的 Jsf 视图 bean 内存泄漏问题。尝试以下链接Memory leak with ViewScoped bean? 中的代码。导航到下一页时,它将清除会话中的视图 bean。

        【讨论】:

        • 你在说什么不是 JSF 特有的。顺便说一句,与这个问题完全无关。
        猜你喜欢
        • 2012-06-01
        • 2014-10-15
        • 2012-10-11
        • 2011-10-16
        • 2011-08-15
        • 2012-08-15
        • 2013-04-04
        • 1970-01-01
        • 2013-12-12
        相关资源
        最近更新 更多