3

I have a custom ServletContextListener that I am using to initialize and start up a Cron4J scheduler.

public class MainListener implements ServletContextListener {
    @Value("${cron.pattern}")
    private String dealHandlerPattern;

    @Autowired
    private DealMoqHandler dealMoqHandler;
}

I am autowiring some objects in the Listener as shown, and would like for Spring to manage the listener's instantiation. I am using programmatic web.xml configuration through WebApplicationInitializer, but so far the Listener isn't being autowired (NullPointerExceptions whenever I try to access the supposedly autowired objects).

I've already tried to add my customer listener after adding the ContextLoaderListener, shown below:

public class CouponsWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(SpringAppConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        container.addListener(new MainListener()); //TODO Not working
    }

I checked these past questions Spring - Injecting a dependency into a ServletContextListener and dependency inject servlet listener and tried to implement the following code inside the contextInitialized method of my listener:

    WebApplicationContextUtils
        .getRequiredWebApplicationContext(sce.getServletContext())
        .getAutowireCapableBeanFactory()
        .autowireBean(this);

However, I just get the following exception:

Exception sending context initialized event to listener instance of class com.enovax.coupons.spring.CouponsMainListener: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:90) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]

How can I make sure that Spring has already finished instantiation before adding my listener?

Community
  • 1
  • 1
Jensen Ching
  • 3,144
  • 4
  • 26
  • 42

2 Answers2

2

My mistake. It turns out the code in the original post is correct, and the listeners are being added in the correct order.

The issue was that I had annotated my custom listener with a @WebListener annotation (Servlet 3.0). This was causing the web app to disregard my addListener() code in WebApplicationInitializer, and instantiate the custom listener AHEAD of Spring's ContextLoaderListener.

The following code block illustrates the ERRONEOUS code:

@WebListener /* should not have been added */
public class CouponsMainListener implements ServletContextListener {
    @Autowired
    private Prop someProp;
}
Jensen Ching
  • 3,144
  • 4
  • 26
  • 42
0

You cannot use new with Spring beans - Java doesn't care about Spring and Spring has no way to modify the behavior of the new operator. If you create your objects yourself, you need to wire them yourself.

You also need to be careful what you do during initialization. When using Spring, use this (simplified) model: First, Spring creates all the beans (calls new for all of them). Then it starts to wire them.

So you must be extra careful when you start to use the autowired fields. You can't always use them right away, you need to make sure that Spring is finished initializing everything.

In some cases, you can't even use autowired fields in @PostProcess methods because Spring couldn't create the bean because of cyclic dependencies.

So my guess is that "whenever I try to access" is too early.

For the same reason, you can't use WebApplicationContextUtils in the WebApplicationInitializer: It hasn't finished setting up Spring, yet.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I just realized while debugging this that manually instantiating the object doesn't allow Spring to autowire it, as you said. Turns out though I made a totally different mistake (detailed in my self-answer). Still, thanks for the clarification. – Jensen Ching Sep 12 '12 at 08:31