如何使用来自webapp的Spring注入启动守护进程

时间:2013-01-14 17:44:46

标签: java spring dependency-injection

我需要在部署战争时启动一个守护进程。守护进程本身使用应该用Spring注入的对象。我做了以下事情:

在web.xml中

...
<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/springapp-servlet.xml</param-value>
</context-param>

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

AppListener.java

public class AppListener implements ServletContextListener {
...
  @Override
  public void contextInitialized(final ServletContextEvent sce) {
      log.info("======================= Begin context init =======================");
      try {
        // final ApplicationContext context = new ClassPathXmlApplicationContext("WEB-INF/springapp-servlet.xml");
        final ApplicationContext context = new ClassPathXmlApplicationContext("src/main/webapp/WEB-INF/springapp-servlet.xml");
      //final ApplicationContext context = new ClassPathXmlApplicationContext("//Users/.../WEB-INF/springapp-servlet.xml");

      final SessionServiceDaemon sessionServiceDaemon = context.getBean(SessionServiceDaemon.class);
      sessionServiceDaemon.start();
    } catch (final Exception e) {
      log.error("Was not able to start daemon",e);
    }
}

SessionServiceDaemon.java

@Service
@Singleton
public class SessionServiceDaemon {

  private final static Logger log = LoggerFactory.getLogger(SessionServiceDaemon.class);

  private final SessionServiceHandler handler;

  @Inject
  public SessionServiceDaemon(final SessionServiceHandler handler) {
    log.info("+++++++++++++++++++++++++++++++ SessionServiceDaemon injected");
    this.handler = handler;
  }

我的springapp-servlet.xml只包含注入所需的包:

<?xml version="1.0" encoding="UTF-8"?>
<beans ...

  <context:component-scan base-package="example" />
    <mvc:annotation-driven />

</beans>

在启动日志中,我看到了预期:

+++++++++++++++++++++++++++++++ SessionServiceDaemon injected

接着是

======================= Begin context init =======================

问题是:然后我得到一个例外,即无论我用哪个路径指向springapp-servlet.xml,该文件都不存在:

org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [src/main/webapp/WEB-INF/springapp-servlet.xml]; nested exception is java.io.FileNotFoundException: class path resource [src/main/webapp/WEB-INF/springapp-servlet.xml] cannot be opened because it does not exist

我尝试了不同的相对路径甚至绝对路径都没有成功。我甚至编辑了上面的代码,并在我尝试加载上下文之后添加了以下内容:

  try {
    log.info(org.apache.commons.io.FileUtils.readFileToString(new File("src/main/webapp/WEB-INF/springapp-servlet.xml")));
  } catch (final Exception e) {
    log.error("Unable to find file",e);
  }

并打印出springapp-servlet.xml的内容就好了。

我的2个问题:

  • 当我能够使用精确显示文件内容时,如何获取“类路径资源[src / main / webapp / WEB-INF / springapp-servlet.xml]无法打开,因为它不存在”来自同一方法的相同路径?
  • 我是否有正确的方法来启动具有注入依赖关系的守护进程?

PS:我使用Tomcat。

1 个答案:

答案 0 :(得分:1)

您正在启动两个不同的spring应用程序上下文。第一个是内置的ContextLoaderListener,可能会从默认位置获取springapp-servlet.xml配置。 (您没有说明是否要指定contextConfigLocation。)

在自定义侦听器中,然后使用带有显式路径的ClassPathXmlApplicationContext构造新的应用程序上下文。在您显示的三行中,只有带有“”WEB-INF / springapp-servlet.xml“的行看起来像是类路径解析的候选者,尽管它实际上取决于您如何配置和启动Tomcat实例。 (即Tomcat的观点是什么类路径?)

无论如何,有更好的方法将Spring应用程序上下文放入servlet / listener中。直接的方法是使用ContextLoaderListener,但是在自定义的servlet / listener中,使用Spring的WebApplicationContextUtils.getWebApplicationContext

Spring也直接支持servlet,包括通过注释配置,HttpServletBean类,甚至直接使用FrameworkServlet