一、一张图讲清过滤器拦截器在SpringMVC请求响应流程情况
- Web服务器 :是用于处理客户端与服务器之间的请求与响应的网络交互过程,Web服务器能处理的请求与响应必须遵循HTTP协议。直白点说,客户端向Web服务器传递的请求数据,和Web服务器向客户端响应的数据都是字符串,或者说Web服务器只能处理静态资源。当客户端发起了HTTP请求,Web服务器首先检查客户端请求的内容是否是静态资源。如果是静态资源,Web服务器会直接找到静态资源返回给客户端。当发现客户端请求的内容是动态内容,Web服务器会把请求转发给Servlet容器来处理。Servlet容器处理完后会把响应转发给Web服务器来转化成符合HTTP协议格式的HTTP响应。
- Servlet容器 :是 Web 服务器为支持 servlet 功能扩展的部分,实现客户端与Web服务器之间的动态交互。直白点说,就是Web服务器理解不了的HTTP请求,交给了可以理解的Servlet容器。然后,Servlet容器把请求解释成Web服务器可以理解的结果,再转发给Web服务器响应客户端的请求。
- Filter过滤器 :过滤器Filter和Servlet一样都是基于 Java 的 Web 组件,由Servlet容器进行管理,来生成动态内容。也就是说,过滤器Filter的初始化init()、过滤处理doFilter()、销毁destroy()等方法的执行都是由Servlet容器来调用的。注意,当Web服务器发现HTTP请求的是动态内容,把请求转发给了Servlet容器。Servlet容器原本首先是去查找对应的Servlet来处理,但是当Filter过滤器存在并且匹配请求时,Servlet容器会先拿Filter过滤器对请求先进行处理一遍,再交给Servlet来处理。由于Filter过滤器是使用回调方式,当Servlet处理完后Filter过滤器会继续对Servlet响应进行再处理。由图可见,Servlet容器的生命周期是比Spring容器更早&更久,所以Spring容器中的Bean是无法注入到过滤器Filter中使用的。这个特性也直接导致Filter一般主要用来对请求和响应进行处理,而不对具体的业务进行处理。
- Interceptor拦截器 :拦截器Interceptor是由Spring管理,存于Spring IOC容器一种组件,也是Spring AOP面向切面编程的一种实现。拦截器是基于动态代理、使用反射机制来实现的。它和Spring IOC中其它组件一样生命周期是由Spring控制,拦截器中是可以注入Spring IOC容器其它Bean进行业务处理的。当然,拦截器也可以实现Filter过滤器全部的作用的。所以,拦截器功能更强大,也建议使用拦截器。
- SpringMVC :是基于Spring的web组件,实现动态请求处理。其核心类DispatcherServlet,通常称之为前端控制器。所有来自客户端的请求,都会由DispatcherServlet进行请求转发,再由它把响应返回给Servlet容器。具体的运行过程见上图,下文也会由源码解读。
过滤器与拦截器的区别在解读部分已经很清楚
二、Filter过滤器在SpringBoot项目中使用说明
原来在Spring项目中配置Filter过滤器都是在web.xml中进行配置的。在SpringBoot项目中没有了web.xml文件,不过有新的配置方式。
1、注解方式
注解方式有两种方案,如下:
@WebFilter
+@Component 或 @Configuration
+(@Order
可选)
@Slf4j
@Order(2)
@Component
@WebFilter(urlPatterns="/*", filterName="filter2")
public class Filter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
log.info("{}初始化完成",this.getClass().getName());
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("{}执行过滤开始....",this.getClass().getName());
filterChain.doFilter(servletRequest,servletResponse);
log.info("{}执行过滤结束....",this.getClass().getName());
}
public void destroy() {
log.info("{}销毁",this.getClass().getName());
}
}
@WebFilter
+@ServletComponentScan("Filter所在包目录")
+(@Order
可选)
@Slf4j
@Order(2)
@WebFilter(urlPatterns="/*", filterName="filter2")
public class Filter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
log.info("{}初始化完成",this.getClass().getName());
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("{}执行过滤开始....",this.getClass().getName());
filterChain.doFilter(servletRequest,servletResponse);
log.info("{}执行过滤结束....",this.getClass().getName());
}
public void destroy() {
log.info("{}销毁",this.getClass().getName());
}
}
@ServletComponentScan("com.mapc.j2ee.filter")
@SpringBootApplication
public class J2eeFilterInterceptorServletApplication {
public static void main(String[] args) {
SpringApplication.run(J2eeFilterInterceptorServletApplication.class, args);
}
}
在SpringBoot入口类添加
@ServletComponentScan
注解,或者自定义一个FilterConfig类添加@ServletComponentScan
+@Configuration
组合注解都可以。
2、编码方式
使用FilterRegistrationBean
注入。
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registerFilter1(){
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
filterRegistrationBean.setFilter(new Filter1());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setUrlPatterns(Collections.singleton("/*"));
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean registerFilter2(){
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
filterRegistrationBean.setFilter(new Filter2());
filterRegistrationBean.setOrder(2);
filterRegistrationBean.setUrlPatterns(Collections.singleton("/*"));
return filterRegistrationBean;
}
}
三、Interceptor拦截器在SpringBoot项目中使用说明
1、继承WebMvcConfigurationSupport
+@Configuration 或 @Component
注解
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
@Slf4j
@Order(2)
public class Interceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("{}请求处理前拦截",this.getClass().getName());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("{}请求处理后返回ModelAndView拦截",this.getClass().getName());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("{}请求处理后返回给前端视图拦截",this.getClass().getName());
}
}