【问题标题】:Injecting dependency in ServletContextListener在 ServletContextListener 中注入依赖项
【发布时间】:2013-11-14 05:06:36
【问题描述】:

我提到了very helpful previous post,但在 ServletContextListener 中注入 bean 时遇到了不同的问题

聆听者

    package sapphire.social.connector.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.web.context.support.WebApplicationContextUtils;

import sapphire.adapter.youtube.YTConnectorMgr;
import sapphire.social.connector.logger.LogManager;

public class AppServletContextListener implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        if (LogManager.isDebugOn()) {
            LogManager
                    .debug("AppServletContextListener ::: contextDestroyed :::");
        }

    }

    @Override
    public void contextInitialized(ServletContextEvent initializingEvent) {
        // TODO Auto-generated method stub
        if (LogManager.isDebugOn()) {
            LogManager
                    .debug("AppServletContextListener ::: contextInitialized :::");
        }

        if (LogManager.isDebugOn()) {
            LogManager
                    .debug("AppServletContextListener ::: contextInitialized ::: WebApplicationApplicationContext : "
                            + WebApplicationContextUtils
                                    .getWebApplicationContext(initializingEvent
                                            .getServletContext()));
        }

        if (LogManager.isDebugOn()) {
            LogManager
                    .debug("AppServletContextListener ::: contextInitialized ::: RequiredWebApplicationApplicationContext : "
                            + WebApplicationContextUtils
                                    .getRequiredWebApplicationContext(initializingEvent
                                            .getServletContext()));
        }

        YTConnectorMgr ytConnectorMgr = (YTConnectorMgr) WebApplicationContextUtils
                .getWebApplicationContext(initializingEvent.getServletContext())
                .getAutowireCapableBeanFactory()
                .autowire(YTConnectorMgr.class,
                        AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);

        if (LogManager.isDebugOn()) {
            LogManager
                    .debug("AppServletContextListener ::: contextInitialized ::: ytConnectorMgr : "
                            + ytConnectorMgr);
        }
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">


    <!-- <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/sapphire-security.xml</param-value>
    </context-param> -->

    <listener>
        <listener-class>sapphire.social.connector.listener.AppServletContextListener</listener-class>
    </listener>

    <servlet>
    <servlet-name>central-config</servlet-name>
        <servlet-class>
                  org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>central-config</servlet-name>
        <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

central-config-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">

    <context:component-scan base-package="sapphire" />

    <mvc:annotation-driven />


    <!-- Start : To by-pass MVC view resolution and pass the response to appropriate 
        media type view resolvers/views Deprecated approach since Spring 3.2.x -->
    <bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="favorPathExtension" value="false"></property>
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="text/xml" />
                <entry key="htm" value="text/html" />
            </map>
        </property>
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/views/" />
                    <property name="suffix" value=".jsp" />
                </bean>
            </list>
        </property>
        <!-- <property name="defaultContentType" value="application/json" /> <property 
            name="defaultViews"> <list> <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" 
            /> </list> </property> -->
    </bean>
    <!-- End : To by-pass MVC view resolution and pass the response to appropriate 
        media type view resolvers/views Deprecated approach since Spring 3.2.x -->


    <task:scheduler id="scheduler" pool-size="5" />

    <task:annotation-driven scheduler="scheduler" />

</beans>

我尝试检索 WebApplicationContext 和 Required WebApplicationContext - 前者为空,后者需要一个 ContextLoaderListener

Fri Nov 15 12:05:55 IST 2013 [Thread-2] AppServletContextListener ::: contextInitialized :::
Nov 15, 2013 12:05:55 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class sapphire.social.connector.listener.AppServletContextListener
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
    at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:84)
    at sapphire.social.connector.listener.AppServletContextListener.contextInitialized(AppServletContextListener.java:44)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4723)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)
    at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Nov 15, 2013 12:05:55 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Error listenerStart
Nov 15, 2013 12:05:55 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/Sapphire] startup failed due to previous errors
Fri Nov 15 12:05:55 IST 2013 [Thread-2] AppServletContextListener ::: contextInitialized ::: WebApplicationApplicationContext : null
Fri Nov 15 12:05:55 IST 2013 [stop children - Catalina:j2eeType=WebModule,name=//tenantarchtst.lntinfotech.com/Sapphire,J2EEApplication=none,J2EEServer=none] AppServletContextListener ::: contextDestroyed :::
Nov 15, 2013 12:05:55 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8081"]
Nov 15, 2013 12:05:55 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8010"]
Nov 15, 2013 12:05:55 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 15184 ms

仅供参考,在ServletContextListener中给出我要注入的bean:

@Component(value = "YTConnectorMgr")
public class YTConnectorMgr extends ConnectorMgr {

    private static int maxWorkerThreads = 5;

    public YTConnectorMgr(int maxWorkerThreads, ConnectorType connectorType) {
        super(maxWorkerThreads, connectorType);
    }

}

我有一个由 DispatcherServlet 处理的单个配置 xml 文件 - 理想情况下,我不需要 ContextLoaderListener!但即使this previous post 也要求使用 ContextLoaderListener。正如 M.Deinum 所指出的,我不应该复制我的豆子!!!

【问题讨论】:

  • 您知道您正在加载配置两次,有效地复制了所有 bean? (ContextLoaderListener 和 DispatcherServlet 构造和应用程序上下文都包含来自 central-config-servlet.xml 的所有内容。而不是 getWebApplicationContext 尝试 getRequiredWebApplicationContext。其中的逻辑让我想知道为什么你不是简单地在ApplicationContext注册这个bean并使用@Scheduled吗?
  • @M.Deinum 实际上,我最初没有配置 ContextLoaderListener,因为它没有任何意义,但我想它是检索 WebApplicationContext 所必需的。已经编辑了我的问题并发布了异常 - 你可以看看吗?
  • 如果您希望 ServletListener 访问 ApplicationContext 它将只能访问根上下文。并且 ContextLoaderListener 需要在您自己的侦听器之前加载/注册(否则尚未创建上下文)。但是你为什么要把事情弄得这么复杂?只需使用依赖注入。将字段添加到您的ServletContextListener 用@Autowired 注释那些字段,而不是进行查找,只需使用您当前的ServletContextListener 实例调用configureBean。为您节省了所有丑陋的 getInstance 方法,您基本上是在利用 spring。
  • @M.Deinum Err... 我想不通“而不是使用您当前的 ServletContextListener 实例调用 configureBean 来代替查找”。是的,我将从 YTConnector 中删除静态内容等,但普通的 Autowired inServletContextListener 将失败!
  • 不,您只需调用正确的方法即可。确保在 AppServletContextListener 之前配置您的 ContextLoaderListener。后者包含@Autowired 注释字段。现在在您的contextInitialized 中只需调用autowire(this)(而不是YTConnectorMgr)。这会将依赖项注入您的侦听器。但我仍然想知道你为什么需要这个监听器?它有什么特别之处,以至于您不能使用 ApplicationContext 将所有内容连接在一起?

标签: spring-mvc spring-3 autowired servletcontextlistener


【解决方案1】:

您可能需要使用 @Autowired 来注入 bean: 试试

@Autowired
private ScheduledThreadPoolExecutor executor;
@Autowired
private ScheduledFuture scheduledFuture;

【讨论】:

  • 我没听明白 - 我正在为 bean factory 获取 NPE,这就是我卡住的地方!自动连接上述实例有什么帮助???
  • 很抱歉,我之前没有看清楚你的问题。后来我试了,发现很奇怪,我用你上面的代码写了一个小演示,成功了!这是演示(dropbox.com/s/2pslys0wrflp8w2/webtest.rar) ---,你可以试试。
猜你喜欢
  • 2011-06-12
  • 1970-01-01
  • 2012-01-26
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 2020-12-20
  • 2020-03-14
  • 2013-03-03
相关资源
最近更新 更多