springboot项目中使用filter踩坑

问题:使用@WebFilter无法注入bean

问题原因: web容器加载顺序导致, 加载顺序是listener——filter——servlet,当项目启动时,filter先于servlet初始化, 而Spring中默认bean的初始化是在Servlet后进行的,所以会注入失败。

解决方式: 1、 如果是web.xml配置, 可将Spring容器改成Listener方式初始化:org.springframework.web.context.ContextLoaderListener。 2、 使用FilterRegistrationBean或者DelegatingFilterProxyRegistrationBean注册filter, 为什么可以这么实现呢?因为FilterRegistrationBean和DelegatingFilterProxyRegistrationBean都继承了AbstractFilterRegistrationBean抽象类,而该抽象类实现了ServletContextInitializer接口, Spring容器初始化时会遍历查找实现ServletContextInitializer接口的bean,并调用onStartup方法注册自定义的filter。3、将filter声明为bean,Spring容器初始化时也会调用onStartup方法注册filter,但该方式无法定义拦截规则, 默认拦截所有请求。

FilterRegistrationBean和DelegatingFilterProxyRegistrationBean区别:
FilterRegistrationBean通过onStartup方法直接注册filter。
DelegatingFilterProxyRegistrationBean是将DelegatingFilterProxy注册到Servlet3.0+的容器中,同时实现了ApplicationContextAware接口,实例ApplicationContext通过通过传入自定义filter的名称查找对应的bean,并生成相应bean的代理对象。

解决

springboot内嵌tomcat容器, 无法通过web.xml的方式配置filter, 下面是springbot创建filter的几种方式。

@WebFilter注解

注意: 需在启动类添加@ServletComponentScan注解进行扫描

@WebFilter(urlPatterns = "/*", filterName = "myFilter")
@Order(2)
public class MyFilter implements Filter {
//myService将无法注入
@Autowired
private MyService myService;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter初始化!");
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进入filter中拦截!");
servletResponse.getWriter().write("hello world!");
}

@Override
public void destroy() {
}
}

问题: 无法注入bean,

使用FilterRegistrationBean方式

public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter);
registrationBean.addInitParameter("targetFilterLifecycle","true");
registrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico");
registrationBean.addUrlPatterns("/*");
registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
return registrationBean;
}

使用DelegatingFilterProxyRegistrationBean方式

public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean(){
DelegatingFilterProxyRegistrationBean filterProxy = new DelegatingFilterProxyRegistrationBean("myFilter");
filterProxy.addUrlPatterns("/*");
filterProxy.addInitParameter("targetFilterLifecycle","true");
filterProxy.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico");
filterProxy.setDispatcherTypes(DispatcherType.REQUEST);
return filterProxy;
}