【问题标题】:JSF SessionScoped managed bean - injection of spring bean is null after restarting serverJSF SessionScoped托管bean - 重新启动服务器后注入spring bean为空
【发布时间】:2012-04-09 01:03:50
【问题描述】:

在一个基于 tomcat 开发的 JSF 2 应用程序中,我有以下 SessionScoped 托管 bean:

@ManagedBean(name = "loginBean")
@SessionScoped
public class LoginBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private String login;
    private String password;

    @ManagedProperty(value = "#{authenticationService}")
    transient private AuthenticationService authenticationService;

    public String login() {

        boolean success = authenticationService.login(login, password); // after restarting tomcat, authenticationService is null here!

        //........
    }
}

authenticationService是spring的@Service:

@Service("authenticationService")
public class AuthenticationServiceImpl implements AuthenticationService, Serializable {

    private static final long serialVersionUID = 1L;

    //....
}

另外,我已经定义了要保存在客户端的会话:

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

问题:

当我早上第一次启动 tomcat 时,LoginBean 工作正常。但是,如果我然后重新启动 tomcat 并立即尝试访问 LoginBean.login(),我会在 authenticationService 上收到 NullPointerException。

我已将authenticationService 定义为瞬态,这样它就不会被保存到会话中。但是重启tomcat时,并没有再次注入对spring beanauthenticationService的引用。

问题:

  1. 为什么开机不重新注入?
  2. 为什么将 authenticationService 定义为瞬态不通知 JSF 重新注入 authenticationService?
  3. 设置javax.faces.STATE_SAVING_METHOD为client会影响问题吗?
  4. 我该如何解决这个问题?如果您的解决方案受到javax.faces.STATE_SAVING_METHOD 值的影响,请说明原因。

【问题讨论】:

  • 我对 Spring 部分一无所知,因为我从未真正使用过它,但我只是想让您知道使用 EJB 时不会出现此问题(这就是 Spring试图取代)。你不应该只创建服务属性transient,因为你基本上是在告诉它永远不应该被序列化。
  • 如果你使用 Spring,那么使用 Spring IoC 容器进行注入总是比使用 JSF 容器更好。这样您甚至可以轻松管理代码。按照这个question's 回答如何将 JSF 与 Spring 集成
  • @BalusC 谢谢!如果我不将服务属性设置为transient,它将在重新启动服务器后被反序列化,但它的所有内部数据都将是陈旧的,而且它不会附加到 Spring `applicationContect'。我想要的服务 bean 是在重新启动期间由 Spring 重新创建和自动装配,就像 Spring 在重新启动之前没有找到保存到磁盘但用户尝试访问的序列化会话时所做的那样重新启动后具有相同会话 ID(相同 cookie)的服务器。请看stackoverflow.com/questions/3778353
  • @Ravi 我认为我的代码应该可以正常工作。请看一下这个示例项目:technology-for-human.blogspot.com/2011/01/…(您可以下载代码并查看)。在全新安装的 tomcat 7 上,这段代码实际上对我有用。问题是,它不适用于我的生产 tomcat(相同版本),它经历了一些配置修改(不确定是哪个,我没有制作它们)。可能是默认情况下tomcat 7不会序列化会话。我还能在哪里更改此设置?请在下面查看 mrembisz 的回答。

标签: spring session jsf dependency-injection


【解决方案1】:

这很可能是由于 tomcat 完成的会话序列化。它正在尝试恢复您的序列化会话,但不会注入 authenticationService。您可以安全地禁用此功能,它很少有任何用途。要禁用它,请查看 tomcat 的 conf/context.xml 并取消注释描述为负责会话持久性管理的部分。

【讨论】:

  • 我想这可能是大多数情况下的解决方案。但是我刚刚签出了conf/context.xml,那部分已经被注释掉了。但很明显,这是由 tomcat 恢复的旧会话(不是那么聪明)引起的。如果我确保在再次访问应用程序之前(重新启动 tomcat 之后)删除我的应用程序 cookie(JSESSIONID) - 自动装配按预期工作正常。在tomcat中是否还有其他地方可以启用我忽略的此功能?
  • 更新:我的错误,您的解决方案确实有效!出于某种原因,我读到我应该评论,而不是取消评论。而且我发现类似的代码可以在其他服务器上运行,而无需禁用 tomcat 会话序列化,因为 SessionScoped bean 实际上不是可序列化的,因为不可序列化成员对象中的传递依赖。因此,在重新启动期间,反序列化失败并重新创建了整个托管 bean(正确地,使用自动装配)。
  • 总结一下,在Tomcat中,如果你使用@ManagedProperty将@ManagedBean或者Spring bean注入到@SessionScoped bean的一个属性中,在conf/context.xml中禁用会话持久化(因为在反序列化期间没有调用@ManagedProperty 来重新注入属性);或在此处使用两种解决方案之一:stackoverflow.com/questions/3778353
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 2014-07-01
  • 2016-05-09
  • 1970-01-01
  • 2012-01-27
  • 2016-05-27
相关资源
最近更新 更多