MemeStorm

Exploring the Spring Framework and Application Development

Session-scoped Beans in Spring 2.0

Posted in All by Jon on the October 10th, 2006

Spring 2.0 introduces a new way of scoping beans. We’ve spoken about singleton scoped beans in the past and there are factory beans too. Now there are session, request and other types of bean scopes. As you might imagine, a Spring bean scoped to the sessions means that it lives as long as the session. This means that if you ask Spring’s IoC container for a bean that is session-scoped, it will instantiate it once only for that particular user’s session—different users in different sessions will get their own bean instances. It gets even cooler if you set this bean as a dependency for another bean that is a singleton. It still works, but in this case Spring injects a smart proxy to handle the dynamic bean swapping (the container bean will get a different dependent bean depending on the session). All of this magic is dead simple to implement and use.

How to do it

Let’s look at how to create a simple session-scoped bean that can be retrieved from the context. If you are using a DispatcherServlet (which you will be if you are using Spring’s MVC) then all you need to do is tag the bean as session-scoped in your application context configuration file. For example:

  <bean id="mybean" class="com.memestorm.ex.MyBean"
        scope=”session”/>

Not much to do…as you’ll see, the only difference is the session attribute. If you aren’t using the DispatcherServlet then you’ll need to add a (small) bit of extra configuration to web.xml:

  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

You need to do this because of the mechanics of how this is implemented, which we’ll look at later. For now remember that if you’re already using Spring’s MVC, you don’t need to do anything. The bean, MyBean is nothing special—here’s the one we use:

    public class MyBean {
    	public MyBean() {
    		System.err.println("In Constructor!!!");
    	}
    }

So now that we’ve defined our bean in our context, how do we use it? Well, just like you’d use any other bean really! Here’s an example of a controller grabbing the bean from our application context:

 // retrieve context
 ApplicationContext ac = org.springframework.web.context.support.
   WebApplicationContextUtils.getRequiredWebApplicationContext(
                       request.getSession().getServletContext());
 // grab bean
 MyBean mb = (MyBean) ac.getBean("mybean");

This is what you’d do anyway. The key isn’t that you have change the way you program - but it’s the way Spring manages the creation of the bean.

What happens?

The bean (MyBean) won’t be created only once (a singleton) for all users—rather it will be created once for each user session. The magic is that it’s effectively tied to the user’s session (and created lazily as a result). Here’s a concrete use case used in the Spring documentation: User Preferences. If your user is logged on and you retrieve a session-scoped bean for the first time, it will be created. While the user is logged on (he has a session) that bean will remain effectively tied to the session so that if you access the bean again (from the context), it will simply retrieve it and not create it again.

You can test this with the supplied example. The index handler just tells me if the session is new (if it is, and you access the bean, you should expect a new instance to be created). The access handler actually tries to retrieve the bean from the context. You’d expect this to create the bean if the session is new, or simply just retrieve it if it’s not. The invalidate handler invalidates the session. Download the example and play - check the console to see the constructor message and when it appears.

More Advanced Work

Let’s look at the situation with dependencies. For example, imagine our session-scoped bean has a dependency on some singleton:

  <bean id="myotherbean" class="com.memestorm.ex.MyOtherBean" />

  <bean id="mybean" class="com.memestorm.ex.MyBean" scope="session">
    <property name="mob" ref="myotherbean" />
  </bean>

What happens now? Well, myotherbean will be created once with the context, and the same instance will be injected into each mybean instance that is created as each user creates a session. Neat huh? But I guess you’d expect that behaviour.

Even More Advanced Work

Let’s flip the injection described in the previous scenario. Imagine you have a bean that has a session-scoped bean as a dependency:

  <bean id="mybean" class="com.memestorm.ex.MyBean" scope="session">
	<property name="mob" ref="myotherbean" />
 	 <aop:scoped-proxy/>
  </bean>
  <bean id=”yetanotherbean” class=”com.memestorm.ex.YetAnotherBean”>
     <property name=”mybean” ref=”mybean” />
  </bean>

You’ll notice I had to do one surprising thing—it’s that magic AOP proxy incantation. Essentially the problem is this: if mybean is only created when accessed from a session, and multiple times for each different session, how do we know what to inject into yetanotherbean because yetanotherbean is a simple singleton created when the Spring context is created?

The answer is of course: it doesn’t and cannot know. So what we have to do is stuff in a proxy that behaves like the object (in fact it goes and grabs the object from the user’s session when you access it). Spring does all the heavy lifting for you in this case - all you need to do is add the scoped-proxy tag. This is pretty neat magic. I’ve included a download to a more advanced application that uses this approach too. Note that to do this proxying Spring needs cglib in the classpath.

Downloads


Print This Post Print This Post

12 Responses to 'Session-scoped Beans in Spring 2.0'

Subscribe to comments with RSS or TrackBack to 'Session-scoped Beans in Spring 2.0'.

  1. Ron Forrester said,

    on October 10th, 2006 at 9:15 pm

    Sweet. Glad you’re back. Thanks for another great explanation of a cool feature.

    Cheers,
    rjf&

  2. Umang Doctor said,

    on October 16th, 2006 at 12:15 pm

    Hi, thank you for your example. I am trying to use a session scoped bean in my application. I am doing the same what you showed in your example, but getting following error:
    —————————-
    Caused by:
    org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
    PropertyAccessException 1:
    org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy53] to required type [com.bglobal.reuse.hibernateApp.value.UserInfo] for property ‘userInfo’; nested exception is java.lang.IllegalArgumentException: No matching editors or conversion strategy found
    Caused by:
    java.lang.IllegalArgumentException: No matching editors or conversion strategy found
    ———————

    Appreciating your time and effort in advance,
    Umang

  3. tech said,

    on October 16th, 2006 at 1:29 pm

    Ron - thanks ;-)

    Umang - that error isn’t coming from my code. I suspect you’ve got something else in your context. It looks like you’re injecting something (maybe the session scoped bean?) that isn’t of the same type as the property in the bean into which you are injecting it.

  4. amir said,

    on April 9th, 2007 at 8:13 am

    i want to have some kind of control on the bean initialization in session bean like ejb. what i mean that i can initialize the bean and then when the usecase completes release or destroy the session bean

  5. joseph said,

    on August 14th, 2007 at 8:07 pm

    This is very cool article for a newbie like me! Thanks. I Learn a lot, a lot from your web.

  6. Ali K said,

    on September 8th, 2007 at 3:52 pm

    Nice article. I was looking for a way to do that and spring provides this nice mechanism through AOP. Thanks for enlightening us on this feature.

  7. Jason said,

    on October 26th, 2007 at 7:41 am

    Thanks, this article saved my ass at work. I had everything right except the RequestContextListener setup in the DD, once this article cleared up that issue for me.

  8. Ravi said,

    on December 20th, 2007 at 9:27 am

    Thanks for the article. The one gotcha (after a day of pain) to watch out for is to add spring-aop dependency jar in the pom (classpath). Spring ignores the tag is ignored and the bean is treated like a singleton when the aop jar did not exist in the classpath.

  9. Josh said,

    on February 27th, 2008 at 7:05 am

    First and foremost, great site and great content.

    Now,

    A - I love the CSS style for the site.
    B - How do I gain access to the session using the DispatchServlet ?

    I am using a MultiActionController and for some reason some session attributes I cannot access. Originally, I added a regular servlet and extracted the attributes I needed, the forwarded it to the Spring application. Although this is a hack, I’m sure there are better ways to do this.

    Any advice?

    Warm regards,

    Josh
    Boston, MA.

  10. Deha Peker said,

    on February 27th, 2008 at 1:53 pm

    How can I create a bean with session scope, but that bean creation shoulld be contingent to some priviledge settings for the user, For example if the admin=true, I want to create the bean otherwise not.
    Basically I don’t want to instantiate that bean for all users session, but just users with admin priviledges. Is it possible to control this with IOC settings in Spring?

  11. tech said,

    on February 28th, 2008 at 6:52 am

    Josh - I believe you just need to add a third parameter of type HttpSession. For example, call your method:
    public ModelAndView viewCart(HttpServletRequest req, HttpServletResponse res, HttpSession ses) { ..}
    Grep for “anyMeaningfulName” in this doc.

  12. tmaus said,

    on August 11th, 2008 at 1:31 am

    thanks for your documentation.

    running into a problem and wanted to know if anyone had the same experience before.

    Setup my spring mvc and deployed into to the springsource application platform (s2ap)

    executing the following line always throws a NullPointerException
    ac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());

    In my partly web.xml I added the one approriate listener:

    org.springframework.web.context.request.RequestContextListener

    Does anyone have a clue or a hint on this issue ???

Leave a Reply