22

I am plugging in Spring to existing Java EE web Application. I have following lines in my web.xml:

<listener>
    <listener-class>com.MyContextListener</listener-class>
</listener> 

And Following MyContextListener class?

public class MyContextListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
       //...
    }
}

What should I do to make MyContextListener be managed by Spring?


Edited:

My assumption is: Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring. How can I achieve, by implementing some interface I suppose. Correct me if I am wrong. Thanks!

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Rudziankoŭ
  • 10,681
  • 20
  • 92
  • 192
  • Do you want to inject Spring beans into this listener? – Maciej Walkowiak Oct 09 '16 at 18:35
  • Why do you need Spring to be aware of this listener? Can you add more info on what you need to achieve? – Luiggi Mendoza Oct 09 '16 at 18:37
  • Is this what you are looking for?. http://stackoverflow.com/questions/8686507/how-to-add-a-hook-to-the-application-context-initialization-event adding the ApplicationListener interface and registering a bean will let you handle the spring life cycle. It will be great if you can give a little more information in question on what your are trying to achieve. Let me know – Aravind R Oct 09 '16 at 18:38
  • @MaciejWalkowiak, can we not inject Spring beans into that listener? – JavaHopper Mar 16 '18 at 16:11
  • Only in a hacky way. I wouldn't recommend, but if you have to look at: https://stackoverflow.com/questions/4746041/spring-injecting-a-dependency-into-a-servletcontextlistener – Maciej Walkowiak Mar 16 '18 at 19:09
  • @LuiggiMendoza, I'm suprised of such types of questions from Spring's apologists. Why need? Just because it is a MUST for any compatible web-container. And the way spring decided to do things breaks everything and causes a lot of troubles and questuion on SO. That is why. – Anton Astafiev Jan 19 '21 at 05:37
  • @AntonAstafiev first, I'm not a spring apologist. Second, there may be another problem that leads to this design, that's what I want to learn so I can provide more help; this thinking on [the XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). These questions were more related to understand the situation.ç – Luiggi Mendoza Jan 19 '21 at 13:25

4 Answers4

8

Well,

We had a similar scenario of configuring an exiting Jersey web services app to use Spring for dependency injection. Our Jersey webapp had extended ContextLoaderListener as follow

public class XServletContextListener extends ContextLoaderListener {
    ... 
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        super.contextInitialized(arg0);
        ....
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        super.contextDestroyed(arg0);
        ....
    }
} 

where ContextLoaderListener is

import org.springframework.web.context.ContextLoaderListener;

We included the jersey-spring bridge with all spring dependencies including applicationContext.xml as follow

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.xxx.*" />
    ....
    ....
</beans>

And obviously needed to make sure that XServletContextListener is included in the web.xml as follow

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>com.xxx.**.XServletContextListener</listener-class>
</listener>

Followed by servlet and its init-param values and servlet mapping. You can obviously adopt annotation config in place of xml confib in which case you would need to use WebListener annotation.

We use a variety of annotations such as

@Component for objects
@Service for services 
@Repository for DAOs
@Controller for controllers/resources 
@ContextConfiguration for tests

Everything is loaded and autowired by Spring framework.

Raf
  • 7,505
  • 1
  • 42
  • 59
  • why did you choose `jersey`? OP didn't mention it – Andrew Tobilko Oct 11 '16 at 12:31
  • 1
    Jersey is just a web layer, nothing more (replace it with spring-mvc as you fancy and it won't affect the question asked). Anyway, this is a solution I developed for one of my projects that was using **jersey** and since I found the solution closely-related to the question being asked hence I shared it here. Just like I said, mention of *jersey* makes no difference – Raf Oct 11 '16 at 13:18
  • What about the original listeners of the application? Did you convert them into Spring beans? – Alessandro C Jun 21 '19 at 13:51
7

What should I do to make MyContextListener be managed by Spring?

It depends on which configuration way you are using. Anyway, you should tell directly Spring to use the class you have declared. That could be done by the following way:

@WebListener
public class MyContextListener implements ServletContextListener { ... }

A class marked with this annotation (the Servlet 3.0 specification, 8.1.4) must implement one of these interfaces

HttpSessionAttributeListener
HttpSessionListener
ServletContextAttributeListener
ServletContextListener (+)
ServletRequestAttributeListener
ServletRequestListener
HttpSessionIdListener

that it actually does.

Personally, I prefer a meta-annotation based approach which makes my configuration shorter and more concise.

Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring.

Yes, Spring will do it for you if you provide some information which could help it to register / configure / create / manage an instance.

The information may be either meta-information (a template that tells how to create an instance, like BeanDefinitions) or a completed instance itself (usually, it gets passed programmatically that, in turn, leads to writing a huge amount of code).

How can I achieve, by implementing some interface I suppose.

You are implementing an interface to make your listener a listener (a class that describes specific methods which will be called at some points of time). Spring, itself, is responsible for guaranteeing such calls at those points of time, placing an object in the existing web infrastructure before.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • If you use `@Component` instead of `@WebListener` then you can `@Autowire`as usual in this class. – T3rm1 May 17 '18 at 09:49
3

Either annotate the class with @WebListener or the method with @Bean

Pankaj Kumar
  • 871
  • 5
  • 12
  • In a Spring-Boot 1.3+ scenario, you need to have the package for the class annotated with WebListener annotation (and WebFilter, WebServlet annotations) fall under the ServletComponentScan annotation package scope. – JoshDM Mar 30 '22 at 21:11
1

Annotate where you create a new instance of MyContextListener with @Bean if using Java Configs with Spring Boot.

UserF40
  • 3,533
  • 2
  • 23
  • 34