简体   繁体   English

在Spring的WebApplicationInitializer中订购监听器

[英]Ordering Listeners in Spring's WebApplicationInitializer

I have a custom ServletContextListener that I am using to initialize and start up a Cron4J scheduler. 我有一个自定义的ServletContextListener,用于初始化和启动Cron4J调度程序。

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. 我在监听器中自动连接一些对象,如图所示,并希望Spring管理监听器的实例化。 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). 我通过WebApplicationInitializer使用程序化web.xml配置,但到目前为止,Listener没有自动装配(每当我尝试访问所谓的自动装配对象时,NullPointerExceptions)。

I've already tried to add my customer listener after adding the ContextLoaderListener, shown below: 我已经尝试在添加ContextLoaderListener之后添加我的客户监听器,如下所示:

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: 我查看过去的问题Spring - 将依赖项注入ServletContextListener依赖注入servlet侦听器,并尝试在我的侦听器的contextInitialized方法中实现以下代码:

    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? 在添加监听器之前,如何确保Spring已经完成实例化?

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). 问题是我用@WebListener注释(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. 这导致Web应用程序忽略我在WebApplicationInitializer中的addListener()代码,并实例化Spring的ContextLoaderListener的自定义侦听器AHEAD。

The following code block illustrates the ERRONEOUS code: 以下代码块说明了ERRONEOUS代码:

@WebListener /* should not have been added */
public class CouponsMainListener implements ServletContextListener {
    @Autowired
    private Prop someProp;
}

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. 你不能在Spring bean中使用new - Java并不关心Spring和Spring无法修改new运算符的行为。 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). 使用Spring时,请使用此(简化)模型:首先,Spring创建所有bean(为所有bean调用new )。 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. 你不能总是立即使用它们,你需要确保Spring完成初始化。

In some cases, you can't even use autowired fields in @PostProcess methods because Spring couldn't create the bean because of cyclic dependencies. 在某些情况下,甚至无法在@PostProcess方法中使用自动装配的字段,因为Spring因循环依赖而无法创建bean。

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. 出于同样的原因,您无法在WebApplicationContextUtils中使用WebApplicationInitializer :它还没有完成设置Spring。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM