【问题标题】:Dependency Injection inside of HttpSessionListener implementationHttpSessionListener 实现内部的依赖注入
【发布时间】:2013-12-26 22:11:24
【问题描述】:

问题:这个注入的依赖总是会从SimpleController返回0

  1. 为什么在尝试对 HttpSessionListener 实现进行依赖注入时,该 bean 的上下文会丢失?
  2. 这背后的原则是什么,我错过/困惑这不起作用?
  3. 我该如何解决这个问题?

Github 上的项目webApp project Source

考虑以下几点:

SessionCounterListener

public class SessionCounterListener implements HttpSessionListener {

  @Autowired
  private SessionService sessionService;

  @Override
  public void sessionCreated(HttpSessionEvent arg0) {
    sessionService.addOne();
  }

  @Override
  public void sessionDestroyed(HttpSessionEvent arg0) {
    sessionService.removeOne();
  } 
}

web.xml

<web-app ...>
    <listener>
        <listener-class>com.stuff.morestuff.SessionCounterListener</listener-class>
    </listener>

</web-app>

applicationContext.xml

<xml ...>

   <!-- Scan for my SessionService & assume it has been setup correctly by spring-->
   <context:component-scan base-package="com.stuff"/>

</beans>

服务:SessionService

@Service
public class SessionService{

  private int counter = 0;

  public SessionService(){}

  public void addOne(){
    coutner++;
  }

  public void removeOne(){
    counter--;
  }

  public int getTotalSessions(){
     return counter;
  }

}

控制器:SimpleController

@Component
public SimpleController
{
  @Autowired
  private SessionService sessionService;

  @RequestMapping(value="/webAppStatus")
  @ResponseBody
  public String getWebAppStatus()
  {
     return "Number of sessions: "+sessionService.getTotalSessions();
  }

}

【问题讨论】:

    标签: spring servlets web-applications dependency-injection web.xml


    【解决方案1】:

    当您像这样在 web.xml 中声明 &lt;listener&gt;

    <listener>
        <listener-class>com.stuff.morestuff.SessionCounterListener</listener-class>
    </listener>
    

    您是在告诉您的 Servlet 容器 实例化listener-class 元素中指定的类。换句话说,这个实例不会由 Spring 管理,因此它不能注入任何东西,并且该字段将保持为null

    这里有workarounds。还有some more

    注意这个

    <!-- Scan for my SessionService & assume it has been setup correctly by spring-->
    <context:component-scan base-package="com.stuff"/>
    

    不是web.xml 中的有效条目。我不知道这是否是您的复制错误。

    【讨论】:

    • @stackoverflow 查看解决方法。您不一定需要将其从 web.xml 中删除。如果这样做,则需要以不同的方式注册它(参见ServletContextServletContainerInitializerWebApplicationInitializer)。否则,您可以简单地从ServletContext 属性中获取当前的WebApplicationContext
    • 所以(和我一起)如果了解您的“解决方法”链接提供的答案。基本上只需从 web.xml 中删除侦听器并实现 ServletContextListener 接口(带有适当的注释)。我应该准备好了?
    • @stack No. ServletContextListenerHttpSessionListener 有不同的用途(参见 javadoc),但它们的注册方式相同,即。 &lt;listener&gt;。在第二个链接中,它显示了如何使用WebApplicationListener。该界面使您可以访问ServletContext,您可以在其中以编程方式注册侦听器。由于您可以访问 Spring 上下文,因此您可以让它提供一个 SessionCounterListener bean 并注册它。
    • @stackoverflow 不要混淆web.xml 和以&lt;beans&gt; 声明开头的spring 上下文文件。 &lt;component-scan&gt; 是在 spring 上下文文件中使用的 Spring 元素,而不是在 Web 部署描述符中。
    • 获得上下文的唯一方法是,如果我调用的每个 DI 实例 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);这似乎是一种可怕而笨拙的做法。所以现在为了让事情顺利进行,我在整个项目中打了大约 8 次不同的电话(根据 requestMappings)
    【解决方案2】:

    这是一个显示实际解决方案的答案。

    你应该像这样修改SessionCountListener,上面的例子就可以了:

    public class SessionCounterListener implements HttpSessionListener {
    
      @Autowired
      private SessionService sessionService;
    
      @Override
      public void sessionCreated(HttpSessionEvent arg0) {
        getSessionService(se).addOne();
      }
    
      @Override
      public void sessionDestroyed(HttpSessionEvent arg0) {
        getSessionService(se).removeOne();
      }
    
      private SessionService getSessionService(HttpSessionEvent se) {
        WebApplicationContext context = 
          WebApplicationContextUtils.getWebApplicationContext(
            se.getSession().getServletContext());
        return (SessionService) context.getBean("sessionService");
      } 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 1970-01-01
      • 2011-01-03
      • 2023-03-14
      • 2014-01-08
      相关资源
      最近更新 更多