1

I want to create a session-scoped bean to monitor activations and passivations of HTTP sessions. The bean is very simple:

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 definition in application context:

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

With this configuration there is no logs from this class, even from the constructor or init() method. Apparently, Spring does not create this bean.
By trial and error I checked that Spring instantiates such a bean when it is needed by another bean, e.g. used by UI. Is there any other (better) way? Is it a bug in Spring? Spring version used: 2.0.8.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
pkalinow
  • 1,619
  • 1
  • 17
  • 43

2 Answers2

2

HttpSessionActivationListener is part of the javax.servlet.http package. That should give you a hint that it should be managed by the Servlet container. In your case, you aren't registering the Listener with your ServletContext, neither through the web.xml or a SerlvetContainerInitializer.

Through web.xml you wouldn't be able to make it both a Spring and Servlet container managed object so instead these workarounds exist, first, second.

If you are using a WebApplicationInitializer, you can instantiate your AnnotationConfigWebApplicationContext, have the SessionLoggingListenerBean bean created, retrieve it and use it with

SessionLoggingListenerBean yourBean = context.getBean(SessionLoggingListenerBean.class);
servletContext.addListener(yourBean);
Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Thanks for the answer. I cannot use WebApplicationInitializer since my Spring is too old. I'll try other options. – pkalinow Dec 12 '13 at 14:32
0

After some experimenting I think it is better not to use Spring for this purpose. I've modified the class to implement also HttpSessionListener and 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());
}

}

and added it to web.xml:

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

From now on, whenever a new session is created, the listener binds to it (session.setAttribute(...)). This is necessary to make the container notice the listener about session activation or passivation.


In case of Spring and sessions - according to this forum thread Spring does not load session beans until they are requested:

Session bean is treated as a special form of "prototype". That means it will follow prototype symantics in creating an instance.

For me this is an unintuitive and not well documented behavior.

pkalinow
  • 1,619
  • 1
  • 17
  • 43