从后台任务中注入依赖项

时间:2013-09-05 20:17:29

标签: spring spring-mvc dependency-injection

我是春天的新手,我正在试图弄清楚如何将对象自动装配到控制器。该对象是在运行时从使用ServletContextListener启动和停止的任务创建的。如何告诉spring应用程序上下文这个对象?

更多详情

我的后台任务是从下面的代码开始的。我希望将alertServer对象连接到控制器。我可以修改这个类吗?

@WebListener
public class ExecutorContextListener implements ServletContextListener
{
   private static Logger log = Logger.getLogger(ExecutorContextListener.class);

   Thread backgroundThread;
   AlertServer alertServer;

   @Override
   public void contextInitialized(ServletContextEvent event)
   {
      // Start the AlertServer
      alertServer = new AlertServer();

      backgroundThread = new Thread(alertServer, "AlertServer");
      backgroundThread.start();

   }

   @Override
   public void contextDestroyed(ServletContextEvent event)
   {
      alertServer.stop();
      try
      {
         backgroundThread.join();
      }
      catch (InterruptedException e)
      {
         log.error("contextDestroyed Exception", e);
      }
   }
}

更新

所提供的评论和答案对于找到解决方案非常有帮助。有了Sotirios Delimanolis和Dave Newton提供的信息,我意识到现在我正在Spring上构建我的解决方案,我真的不需要首先使用ServletContextListener。我真正想要做的就是启动一个可供Spring控制器使用的后台线程,所以我把这个代码放在我的servlet-context.xml中,然后我就开始运行了。

<beans:bean id="alertServer" class="com.springmvcproj.AlertServer">
    <beans:property name="serverPort" value="56543" />
</beans:bean>

<beans:bean id="AlertServerThread" class="java.lang.Thread" init-method="start">
  <beans:constructor-arg ref="alertServer"/>
</beans:bean>

1 个答案:

答案 0 :(得分:1)

正如Dave Newton在评论中所说,Spring只能将它管理的bean注入其管理的其他bean中。注释为@WebListener的类是由servlet容器管理的类,因此永远不会出现在Spring上下文中。即使它确实存在(因为你创建了一个bean条目),它也不会与servlet容器使用的条目相同。

解决这个问题的方法是使用Spring的WebApplicationInitializer代替(或旁边)使用web.xml描述符。此接口提供onStartup(ServletContext)方法,您可以像web.xml@WebXXX一样注册Servlet,过滤器和监听器。像

这样的东西
public void onStartup(ServletContext container) throws ServletException {
// Create the 'root' Spring application context
    final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(YourApplicationContext.class); // or some xml file
    rootContext.refresh();

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

    // Create the dispatcher servlet's context
    final AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
    dispatcherContext.register(DispatcherContext.class);

    final ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
    dispatcher.setAsyncSupported(true);
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");

    container.addListener(dispatcherContext.getBean(ExecutorContextListener.class)));

    ...// more registrations
}

因此,上面假设您的AnnotationConfigWebApplicationContext dispatcherContext包含ExecutorContextListener类型的bean。由于Spring正在管理此bean,因此您可以添加@Autowired@Inject以在此AlertServerServletContextListener类中注入相同的@Controller实例。在这种情况下,您不会在contextInitialized()方法中初始化它。

第二种选择是

  1. AlertServer对象添加为ServletContext
  2. 中的属性
  3. ServletContext注入您的@Controller课程。
  4. AlertServer属性中检索ServletContext对象。
  5. 以上是可能的,因为contextInitialized()方法总是在任何控制器开始处理请求之前运行。