龙空技术网

一张图讲清楚SpringMVC运行原理,拦截器&过滤器区别与执行顺序

梅子抱福 208

前言:

现在我们对“mvc过滤器的工作原理”大体比较注意,各位老铁们都想要分析一些“mvc过滤器的工作原理”的相关资讯。那么小编也在网上网罗了一些有关“mvc过滤器的工作原理””的相关文章,希望大家能喜欢,你们一起来学习一下吧!

一、一张图讲清过滤器与拦截器在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());

}

}

标签: #mvc过滤器的工作原理