作者注:转载请注明出处
1、问题背景:
最近项目需要,需要在filter中添加拦截用户的角色,判断为一体化角色时,如果用户首次登录,需要强制一体化角色设置支付密码,在代码实现时,filter中无法注入Service中的RoleUtils工具和调用其它系统的接口,获取到注入的参数为null。
2、问题探究:
在项目启动时,监听器listener最先初始化,然后是过滤器filter,最后是servlet。 Spring监听器在启动时会读取spring配置文件,进行spring容器的初始化。springMVC的dispatcherServlet初始化时会读取springMVC的配置文件,进行springMVC容器的初始化。Spring容器初始化时会实例化各个bean。
过滤器是servlet规范中定义的,并不归spring容器管理,也无法直接注入spring中的bean,所以在filter中无法注入spring的实例。
3、解决办法:
在Filter的初始化init(FilterConfig filterConfig)方法中,获取Spring的上下文,并获取到bean.
eg:ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(filterConfig.getServletContext());
RoleUtils bean = context.getBean(RoleUtils.class);
this.roleUtils = bean;
以上即可解决Filter无法注入实例的问题。
以下是代码示例:
public class CheckPasswordFilter implements Filter {
public RoleUtils roleUtils;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(filterConfig.getServletContext());
RoleUtils bean = context.getBean(RoleUtils.class);
this.roleUtils = bean;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//在此处即可调用 roleUtils,进行下一步的业务判断
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
补充:[spring中WebApplicationContextUtils类说明]
WebApplicationContextUtils是一个抽象类,其提供了一个很便利的方法来获取spring应用的上下文即WebApplicationContext。
其中的静态方法getWebApplicationContext(ServletContext sc),提供一个ServletContext 类型参数即可。
其原理十分简单,在spring容器初始化的方法org.springframework.web.context.ContextLoader.initWebApplicationContext(ServletContext)中通过servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);已经将WebApplicationContext的实例放入ServletContext 中了。
然后在工具类的org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(ServletContext)中就可以通过传入的ServletContext参数获取到WebApplicationContext实例了。