title: Can't get session scoped bean on session timeout
body: <p>I need to get a proxied session-scoped bean on the <code>HttpSessionListener.sessionDestroyed()</code>. The objective is doing a session cleanup when it gets destroyed (either by <code>invalidate()</code> or timeout). I added the <code>ContextLoaderListener</code> to expose the context and got the bean through <code>WebApplicationContextUtils.getWebApplicationContext()</code>.</p>
  
  <p>Everything works fine if I invalidate the session myself in a Servlet, but when session times out I get an <code>Scope 'session' is not active for the current thread;</code>. I understand that the problem happens for the cleanup is being done by a internal thread of the Servlet engine, but I still need to  be able to get this bean from a <code>HttpSessionListener</code>.</p>
  
  <p>I've seem many of the same question around, no one got a solution, this is why I'm asking again.</p>
  
  <p>My <strong>applicationContext.xml</strong> has no bean declaration, as I'm using annotations. </p>
  
  <p>This the <strong>bean</strong> I need to access when session times out:</p>
  
  <pre class="lang-java prettyprint-override"><code>@Component
  @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
  public class Access {
  
      static private int SERIAL = 0;
  private int serial;
  
      public Access() {
              serial = SERIAL++;
      }
  
      public int getSerial() {
              return serial;
      }
  }
  </code></pre>
  
  <p>This is the <strong>controller</strong> that either <code>create</code> or <code>destroy</code> the session manually.</p>
  
  <pre class="lang-java prettyprint-override"><code>@Controller
  public class Handler {
  
      @Autowired
      Access access;
  
  
      @RequestMapping("/create")
      public @ResponseBody String create() {
          return "Created "+access.getSerial();
      }
  
      @RequestMapping("/destroy")
      public @ResponseBody String destroy(HttpSession sess) {
          int val = access.getSerial();
          sess.invalidate();
          return "Destroyed "+val;
      }
  
  }
  </code></pre>
  
  <p>And this is the <strong>HttpSessionListener</strong> that listen to the session destruction, <strong><em>where I need to access the the contents of the <code>Access</code> session scoped bean</em></strong>.</p>
  
  <pre class="lang-java prettyprint-override"><code>public class SessionCleanup implements HttpSessionListener {
  
  @Override
  public void sessionDestroyed(HttpSessionEvent ev) {
  
      // Get context exposed at ContextLoaderListener
      WebApplicationContext ctx = WebApplicationContextUtils
          .getWebApplicationContext(ev.getSession().getServletContext());
  
      // Get the beans
      Access v = (Access) ctx.getBean("access");
  
      // prints a not-null object
      System.out.println(v);
  
      // this line raise the exception
      System.out.println(v.getSerial());
  
      }
  
  
      @Override
      public void sessionCreated(HttpSessionEvent ev) {/*Nothing to do*/}
  
  }
  </code></pre>
  
  <p>The exception below is raised at <code>v.getSerial()</code>.</p>
  
  <pre><code>Ago 14, 2012 11:44:58 PM org.apache.catalina.session.StandardSession expire
  SEVERE: Session event listener threw exception
  org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.access': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
      at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
      at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:654)
      at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:605)
      at model.Access$$EnhancerByCGLIB$$438f41a5.toString(&lt;generated&gt;)
      at java.lang.String.valueOf(String.java:2902)
      at java.io.PrintStream.println(PrintStream.java:821)
      at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:242)
      at service.SessionCleanup.sessionDestroyed(SessionCleanup.java:24)
      at org.apache.catalina.session.StandardSession.expire(StandardSession.java:709)
      at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:576)
      at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:712)
      at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:697)
      at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1364)
      at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1649)
      at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
      at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
      at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1638)
      at java.lang.Thread.run(Thread.java:722)
  Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
      at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
      at org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:328)
      ... 19 more
  </code></pre>
  
  <p>Finally, here is my <strong>web.xml</strong></p>
  
  <pre class="lang-xml prettyprint-override"><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;web-app 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns="http://java.sun.com/xml/ns/javaee" 
      xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
      id="WebApp_ID" version="2.5"&gt;
  
    &lt;display-name&gt;session-listener-cleanup&lt;/display-name&gt;
  
  
      &lt;context-param&gt;
          &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
          &lt;param-value&gt;/WEB-INF/spring-config.xml&lt;/param-value&gt;
      &lt;/context-param&gt;
  
  
      &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.request.RequestContextListener&lt;/listener-class&gt;
      &lt;/listener&gt;
  
      &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
      &lt;/listener&gt;
  
  
      &lt;listener&gt;
        &lt;listener-class&gt;service.SessionCleanup&lt;/listener-class&gt;
      &lt;/listener&gt;
  
  
      &lt;servlet&gt;
          &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
          &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
          &lt;init-param&gt;
              &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
              &lt;param-value&gt;/WEB-INF/spring-config.xml&lt;/param-value&gt;
          &lt;/init-param&gt;
          &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
      &lt;/servlet&gt;
  
      &lt;servlet-mapping&gt;
          &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
          &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
      &lt;/servlet-mapping&gt;
  
  
      &lt;session-config&gt;
        &lt;session-timeout&gt;1&lt;/session-timeout&gt;
      &lt;/session-config&gt;
  
  
  &lt;/web-app&gt;
  </code></pre>
  
  <p>As I've said, everything goes nice when I invalidate the session at the controller's method <code>destroy</code>.</p>
  
  <p><strong>UPDATE 1: POSSIBLE SOLUTIONS FOUND</strong></p>
  
  <p>The problem happens because a request is needed in order to Spring access session beans. Event though we have a Context associated to the Thread, there is no request.</p>
  
  <p>There are some possible choices here:</p>
  
  <ol>
  <li>Implement the interface DisposableBean, as suggested by <strong>alexwen</strong>. This would imply in moving business logic to the model object<a href="https://stackoverflow.com/a/11965010/179138"> [here]</a>;</li>
  <li>Implement the <code>DestructionAwareBeanPostProcessor</code> also suggested by <strong>alexwen</strong>. This one would mean that you would need to check if the bean being disposed is a <code>Access</code> or not before doing any disposal<a href="https://stackoverflow.com/a/11965010/179138"> [here]</a>;</li>
  <li>Retrieve the bean directly from the session. This way is not a very good one, as you use an undocumented behavior to achieve the result, but does work<a href="https://stackoverflow.com/a/11979178/179138"> [here]</a>;</li>
  <li>Mock a servlet request and bind it's attributes to the Thread through <code>RequestContextHolder</code>. This also leads to undocumented behavior, able of being changed in future releases<a href="http://forum.springsource.org/showthread.php?28389-Access-session-scoped-bean-via-HttpSessionListener&amp;p=280143#post280143" rel="nofollow noreferrer"> [here]</a>;</li>
  </ol>
  
  <p>I didn't chose the last two, for they're not documented. Also, I didn't like the idea of scavenging every bean after a specific one. As I also don't want to mix the business logic into my model beans, I ended up by creating a <code>@Service</code> that creates the bean and also have a <code>destroy</code> method. </p>
  
  <p>This method is responsible by the disposal of the access bean. I implemented the <code>DisposableBean</code> interface on the <code>Access</code> and injected the <code>AccessManager</code> service to the  <code>Access</code> bean and call the service <code>destroy</code> method. The service look like this:</p>
  
  <pre class="lang-java prettyprint-override"><code>@Service
  public class AccessManager {
  
      @Bean(name="access", destroyMethod="destroy")
      @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
      @Autowired
      public Access create(HttpServletRequest request) {
          // creation logic
      }
  
  
      public void destroy(Access access) {
          // disposal logic
      }
  
  }
  </code></pre>