Does CDI Injection Of SessionScoped Beans Into A Servlet Work?

CDI managed beans are injectable intro Servlets. But: are SessionScoped instances correctly associated with requests belonging to a given session?

The following servlet injects a @SessionScoped SessionStore managed bean and stores the recent URI as payload. The content of the HTTP header, as well as, the number of SessionStore instances are printed as well:


@WebServlet(name = "FrontController", urlPatterns = {"/FrontController/*"})
public class FrontController extends HttpServlet {

    @Inject
    SessionStore store;
   
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            String payload = store.getPayload();
            final PrintWriter out = response.getWriter();
            Enumeration headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String value = request.getHeader(name);
                out.println(name + " : " + value);
            }

            String uri = request.getRequestURI();
            out.println("Payload: " + payload);
            out.println("# of sessions : " + SessionStore.INSTANCE_COUNT.get());
            store.setPayload(uri);
        }
        
    }

The SessionStore managed bean increments on each new session the instance counter. Accessing the servlet in a new browser should increment the counter:


@SessionScoped
public class SessionStore implements Serializable{
    
    public static AtomicLong INSTANCE_COUNT = new AtomicLong(0);
    
    private String payload;
    
    @PostConstruct
    public void onNewSession(){
        INSTANCE_COUNT.incrementAndGet();
    }

    public String getPayload() {
        return payload;
    }

    public void setPayload(String payload) {
        this.payload = payload;
    }

    @PreDestroy
    public void onSessionDestruction(){
        INSTANCE_COUNT.decrementAndGet();
    }
    
}

Each new browser window (not a tab) creates a new session, what causes the creation of a new SessionStore instance. DI of @SessionScoped CDI beans into plain servlets works as expected. Opening three browsers generates the following output:


host : localhost:8080
user-agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:13.0) Gecko/20100101 Firefox/13.0.1
accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language : en-us,en;q=0.5
accept-encoding : gzip, deflate
connection : keep-alive
cookie : JSESSIONID=0d84f4c63e6a10054c92dbdf4584
cache-control : max-age=0
Payload: /servlets-and-cdi/FrontController
# of sessions : 3

The Maven 3 project servlets-and-cdi was pushed into the repo: http://kenai.com/projects/javaee-patterns/sources/hg/show/servlets-and-cdi?rev=428

Comments:

Small remark: the Enumeration headerNames needs to be an Enumeration<String> to get the code to compile (it is correct at the Kenai repo BTW)

Posted by Christiaan Ypma on August 11, 2012 at 07:58 PM CEST #

Can you please explain how the servlet instances are managed? Because apparently your example shouldn't work. I mean we have a singleton (FrontController) in which we inject a narrower scope instance (SesstionStore). Shouldn't we end up with a instance of FrontController configured with a SessionStore object that is particular to some user? The SessionStore available for that user will be injected into a servlet accessed by everybody else. Can you please explain a little bit how the container avoid this situation? Thank you.

Posted by Andrei Rugina on August 15, 2012 at 09:07 PM CEST #

Hi,
This is a very cool feature, quite amazing. I am using spring injection now, but this sounds way too good. i'm just wondering how cdi works: i mean injection is done on each http request ? Thank you

Posted by violeta marinescu on August 17, 2012 at 11:57 PM CEST #

Really interesting test as I noticed in a lot of pages people testing instances using System.identityHashCode. I have a question for you, in your example it would make a difference changing: @Inject
SessionStore store; to @Inject
Instance<SessionStore> store? and get the store instance using store.get()?

Thanks.

Posted by NauticalMike on February 17, 2013 at 12:32 AM CET #

Thanks, nice post

Posted by Binh Nguyen on January 28, 2016 at 12:35 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License