spring dependency injection is not working in a class annotated with @WebListener

1k views Asked by At

I tried constructor based Dependency injection in TestAppListener class which implements ServletContextListener. I got this error Exception sending context initialized event to listener instance of class [com.example.listener.TestAppListener].

I searched stack overflow but I couldn't find any solution for this scenario. Please any one help me in sort out this. I placed Implementation classes in META-INF.services folder also. My understanding is there is some problem in constructor dependency injection but this way of DI is need for my situation, because in real time I want to create datasource connection inside startup method.

Find all my classes below which i'm using,

@WebListener
public class TestAppListener implements ServletContextListener {

private static TestDao dao;

public TestAppListener(TestDao dao){
    this.dao = dao;
}
public TestAppListener(){}

@Override
public void contextInitialized(ServletContextEvent sce) {
    dao = ServiceLoader.load(TestDao.class).iterator().next();
    dao.startUp();
    System.out.println("Context initialized method called");
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
    System.out.println("Context destroyed method called");
    dao.shutDown();
}

}

public interface TestDao {

void startUp();

void shutDown(); 

}

public class TestDaoImpl implements TestDao {
@Override
public void startUp() {
    System.out.println("Database is initialized");
}

@Override
public void shutDown() {
    System.out.println("Database is initialized");
}

}

@Configuration
public class SpringConfig {

public SpringConfig() {
}

@Bean
public ServletListenerRegistrationBean<ServletContextListener> listenerRegistrationBean() {
    ServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean<>();
    bean.setListener(new TestAppListener());
    return bean;
}

}

2

There are 2 answers

1
Lee Greiner On

Change private static TestDao dao to private final TestDao dao. Spring doesn't allow statics to be used as targets for injection. Also, your TestDaoImpl class needs to be a component or a bean defined in a Spring configuration file.

0
Hantsy On

The Servlet @WebListeners are handled by Servlet containers(tomcat/Jetty) when the container is starting. So they know nothing about Spring.

For more details, see discussion in this issue.

A workaround solution is replace the @WebListener with Spring's @Component, thus you can inject Spring beans(declare your Dao as spring beans) into the listeners directly.

BTW, you have to add @ServletComponentScan on your Spring Boot application class to activate it.

I created an example project to demo @WebServlet, @WebFilter and @WebListener.