过滤器&监听器中注入Bean的问题

上次碰到一个需求需要对用户等登录行为进行统计,所以需要对用户的Session生命周期进行监听
ssm项目中比较简单只需要自定义一个j监听器类实现HttpSessionListener接口然后实现里边的
即可,如下图

public class LoginSessionListener implements HttpSessionAttributeListener, HttpSessionListener {
	public void sessionCreated(HttpSessionEvent var1){
	}

    public void sessionDestroyed(HttpSessionEvent var1){
    }
}

然后在web.xml中像注册Spring初始化监听器一样注册这个监听器就行
但是在对用户进行操作的时候发现了问题:由于Spring启动对IOC容器初始化也是监听的Servlet的初始化之后才开始初始化,但是Servlet的初始化是由Servlet容器在启动时初始化的(一般我们使用的较多的就是Tomcat),然后在初始化完Servlet之后在对过滤器,监听器进行初始化;这样就导致一个问题——由于监听器是有Servlet容器进行初始化的,他执行在Spring IOC容器初始化之前,导致我们自己本身定义的监听器不能被Spring初始化到IOC容器,就不能使用Spring的依赖注入特性了,这个明显是不行的
但是仔细一想Ioc容器时初始化之后是保存在全局的Servlet上下文中的,在session的生命周期事件监听中都会传入一个HttpSessionEvent对象,该对象就是事件对象,里边包含了触发该事件的session对象,然后我们就可以从HttpSessionEvent中获取session对象,再获取Servlet上下文对象,然后从servlet上下文中取出Ioc容器对象也就是ApplicationContext对象;通过百度得知Ioc容器存放在Servlet上下文中的键是在WebApplicationContext这个接口类中,它里边有一些静态常量,如下

public interface WebApplicationContext extends ApplicationContext {
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_GLOBAL_SESSION = "globalSession";
    String SCOPE_APPLICATION = "application";
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

    ServletContext getServletContext();
}

其中第一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 就是Ioc容器保存在Servlet上下文中的键,由此我们可以直接得到Ioc容器,然后再去除我们想要的Service类等,如下

	ApplicationContext applicationContext = (ApplicationContext)session.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	UsersService usersService = applicationContext.getBean(UsersService.class);

除了这种之外还有一种实现方法,Spring针对这种情况提供的有一个工具类WebApplicationContextUtils,有一个getWebApplicationContext方法,传入一个ServletContext对象返回一个WebApplicationContext对象,就是前边存放静态常量的那个接口类,它实际上是Application的一个子接口,是Spring在Web环境下的默认接口类;获取这个类之后就可以直接获取我们想要的Bean了,如下

	WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
	UsersService usersService = applicationContext.getBean(UsersService.class);

然后再对这个操作进行一个简单的封装

private <T> T getBeanFromServletContext(ServletContext servletContext, Class<T> requireType) {
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        return context.getBean(requireType);
    }

想从Ioc容器获取什么bean就可以直接调用这个方法传入ServletContext和所需要的Bean的class类对象就可以了
本来这个方式实现是没什么问题的,但是我在实际使用中却发现了一个问题,注入的Service类中所依赖的Mapper类对象为空,这就导致功能仍然不能实现,这里先记录一下,将来有时间再深入研究这个问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值