【问题标题】:Session-scoped bean not instantiated会话范围的 bean 未实例化
【发布时间】:2013-12-30 21:34:47
【问题描述】:

我想创建一个会话范围的 bean 来监控 HTTP 会话的激活和钝化。 bean 很简单:

package my.log;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

import org.apache.log4j.Logger;

public class SessionLoggingListenerBean implements HttpSessionActivationListener {
    private final Logger LOG = Logger.getLogger(this.getClass());

    public SessionLoggingListenerBean() {
        LOG.info("SessionLoggingListenerBean starting");
    }

    public void init() {
        LOG.info("SessionLoggingListenerBean init");
    }

    public void sessionDidActivate(HttpSessionEvent event) {
        LOG.info("Session " + event.getSession().getId() + " activated");
    }

    public void sessionWillPassivate(HttpSessionEvent event) {
        LOG.info("Session " + event.getSession().getId() + " will passivate");
    }
}

应用上下文中的 Bean 定义:

 <bean id="sessionLoggingListenerBean" class="my.log.SessionLoggingListenerBean" scope="session" init-method="init" lazy-init="false"/>

有了这个配置,这个类就没有日志,即使是构造函数或 init() 方法。显然,Spring 没有创建这个 bean。
通过反复试验,我检查了 Spring 在另一个 bean 需要它时实例化了这样一个 bean,例如由 UI 使用。还有其他(更好的)方法吗?这是Spring中的错误吗? 使用的 Spring 版本:2.0.8。

【问题讨论】:

    标签: java spring session servlets


    【解决方案1】:

    HttpSessionActivationListenerjavax.servlet.http 包的一部分。这应该给你一个提示,它应该由Servlet 容器管理。在您的情况下,您没有通过ServletContext 注册Listener,也不是通过web.xmlSerlvetContainerInitializer

    通过web.xml,您将无法使其同时成为 Spring 和 Servlet 容器托管对象,因此存在这些解决方法,firstsecond

    如果您使用的是WebApplicationInitializer,您可以实例化您的AnnotationConfigWebApplicationContext,创建SessionLoggingListenerBean bean,检索它并使用它

    SessionLoggingListenerBean yourBean = context.getBean(SessionLoggingListenerBean.class);
    servletContext.addListener(yourBean);
    

    【讨论】:

    • 感谢您的回答。我不能使用 WebApplicationInitializer,因为我的 Spring 太旧了。我会尝试其他选项。
    【解决方案2】:

    经过一些实验,我认为最好不要为此目的使用 Spring。我已经修改了这个类来实现 HttpSessionListener 和 Serializable:

    public class SessionLoggingListener implements HttpSessionListener,
        HttpSessionActivationListener, Serializable {
    private static final long serialVersionUID = -763785365219658010L;
    private static final Logger LOG = Logger.getLogger(SessionLoggingListener.class);
    
    public SessionLoggingListener() {
        LOG.info("SessionLoggingListener created");
    }
    
    public void sessionDidActivate(HttpSessionEvent event) {
        LOG.info("Session " + event.getSession().getId() + " activated");
    }
    
    public void sessionWillPassivate(HttpSessionEvent event) {
        LOG.info("Session " + event.getSession().getId() + " will passivate");
    }
    
    public void sessionCreated(HttpSessionEvent event) {
        final HttpSession session = event.getSession();
        LOG.info("Session " + session.getId() + " created. MaxInactiveInterval: " + session.getMaxInactiveInterval() + " s");
        session.setAttribute(this.getClass().getName(), this);
    }
    
    public void sessionDestroyed(HttpSessionEvent event) {
        LOG.info("Session " + event.getSession().getId() + " destroyed");
        event.getSession().removeAttribute(this.getClass().getName());
    }
    
    }
    

    并将其添加到 web.xml:

    <listener>
        <listener-class>
            evo.log.SessionLoggingListener
        </listener-class>
    </listener>
    

    从现在开始,每当创建新会话时,侦听器都会绑定到它 (session.setAttribute(...))。这是使容器通知侦听器有关会话激活或钝化的必要条件。


    在 Spring 和会话的情况下 - 根据 forum thread Spring 在请求之前不会加载会话 bean:

    会话 bean 被视为“原型”的一种特殊形式。这意味着它将在创建实例时遵循原型语义。

    对我来说,这是一种不直观且没有充分记录的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-26
      • 2017-01-22
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多