3

Problem: This injected dependency will always return 0 from SimpleController

  1. Why does the context get lost for this bean when trying to do dependency injection into an HttpSessionListener implementation?
  2. What is principles behind this am I missing/confusing for this not to be working?
  3. How do I fix this?

Project on Github webApp project Source

Consider the following:

SessionCounterListener

public class SessionCounterListener implements HttpSessionListener { @Autowired private SessionService sessionService; @Override public void sessionCreated(HttpSessionEvent arg0) { sessionService.addOne(); } @Override public void sessionDestroyed(HttpSessionEvent arg0) { sessionService.removeOne(); } } 

web.xml

<web-app ...> <listener> <listener-class>com.stuff.morestuff.SessionCounterListener</listener-class> </listener> </web-app> 

applicationContext.xml

<xml ...> <!-- Scan for my SessionService & assume it has been setup correctly by spring--> <context:component-scan base-package="com.stuff"/> </beans> 

Service: SessionService

@Service public class SessionService{ private int counter = 0; public SessionService(){} public void addOne(){ coutner++; } public void removeOne(){ counter--; } public int getTotalSessions(){ return counter; } } 

Controller: SimpleController

@Component public SimpleController { @Autowired private SessionService sessionService; @RequestMapping(value="/webAppStatus") @ResponseBody public String getWebAppStatus() { return "Number of sessions: "+sessionService.getTotalSessions(); } } 

2 Answers 2

4

When you declare a <listener> in web.xml like so

<listener> <listener-class>com.stuff.morestuff.SessionCounterListener</listener-class> </listener> 

you are telling your Servlet container to instantiate the class specified in the listener-class element. In other words, this instance will not be managed by Spring and it will therefore not be able to inject anything and the field will remain null.

There are workarounds to this. And some more.

Note that this

<!-- Scan for my SessionService & assume it has been setup correctly by spring--> <context:component-scan base-package="com.stuff"/> 

is not a valid entry in web.xml. I don't know if that was a copy mistake on your part.

Sign up to request clarification or add additional context in comments.

6 Comments

@stackoverflow See the workarounds. You don't necessarily need to remove it from web.xml. If you do, you need to register it differently (see ServletContext, ServletContainerInitializer, and WebApplicationInitializer). Otherwise, you can simply get the current WebApplicationContext from the ServletContext attributes.
So (bare with me) If understand the answers supplied by your 'workarounds' link. Essentially by just removing the listener from from the web.xml and implementing the ServletContextListener interface (with appropriate annations). I should be all set?
@stack No. ServletContextListener has a different purpose than an HttpSessionListener (see the javadoc) but they are registered the same way, ie. <listener>. In the second link, it shows how to use WebApplicationListener. That interface gives you access to the ServletContext where you can programatically register a listener. Since you have access to the Spring context, you can have it provide a SessionCounterListener bean and register that.
@stackoverflow Don't confuse web.xml and spring context files, that start with a <beans> declaration. <component-scan> is a Spring element used in a spring context file, not in a web deployment descriptor.
The only way i can get my context is if every DI instance I call SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); This seems like a terrible, clumsy way of doing this. So now to get things working I make this call about 8 different times through out my project (on requestMappings)
|
0

This is an answer here that shows the actual solution.

You should modify SessionCountListener like this, and the above example will work:

public class SessionCounterListener implements HttpSessionListener { @Autowired private SessionService sessionService; @Override public void sessionCreated(HttpSessionEvent arg0) { getSessionService(se).addOne(); } @Override public void sessionDestroyed(HttpSessionEvent arg0) { getSessionService(se).removeOne(); } private SessionService getSessionService(HttpSessionEvent se) { WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext( se.getSession().getServletContext()); return (SessionService) context.getBean("sessionService"); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.