1.Filter
Filter过滤器是服务端的一个组件,是基于servlet实现从客户端访问服务端web资源的一种拦截机制,对请求request和响应response都进行过滤,依赖于serverlet容器。用时,实现Filter接口,在web.xml里配置对应的class还有mapping-url,springboot工程可以通FilterRegisteration配置后,设置要过滤的URL,特别注意:两种方式过滤器都是有序的,谁在前就先调用谁。
定义过滤器后会重写三个方法,分别是init(),doFilter(),和destory()
(1).void init(FilterConfig config)
用于完成Filter的初始化。
(2).void destory()
用于Filter销毁前,完成某些资源的回收。
(3).void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
实现过滤功能,即对每个请求及响应增加的额外的预处理和后处理。,执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。
@Component
public class TestFilter implements Filter {
private Logger log = LoggerFactory.getLogger(TestFilter.class);
@Override
public void init(FilterConfig filterConfig) {
System.out.println("进入TestFilter过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
// 请求放行
filterChain.doFilter(servletRequest, servletResponse);
log.info("进入TestFilter过滤器");
}
@Override
public void destroy() {
log.info("进入TestFilter过滤器destroy销毁");
}
}
2.Interceptor
拦截器,顾名思义,他的作用就是拦截,这个要和过滤器区分开,过滤器依赖serverlet容器,获取request和response处理,是基于函数回调,简单说就是“去取你想取的”,拦截器是通过java反射机制,动态代理来拦截web请求,是“拒你想拒绝的”,他只拦截web请求,但不拦截静态资源,Struts2里面就是将拦截器串联,实现对请求的处理
@Component
public class TestInterceptor implements HandlerInterceptor {
private static Logger logger = LoggerFactory.getLogger(TestInterceptor.class);
/**
* 这个方法是在controller调用之前调用,通过返回true或者false决定是否进入Controller层
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) {
try {
logger.info("进入TestInterceptor拦截器");
return true;
} catch (Exception e) {
}
return true;
}
/**
* 在请求进入控制层之后调用,但是在处理请求抛出异常时不会调用
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/**
* 在请求处理完成之后,也就是在DispatherServlet渲染了视图之后执行,也就是说这个方法必定是执行,
* 包含异常信息,它的主要作用就是清理资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
再看一下springBoot里面的配置,实现WebMvcConfigurer 接口,重写addInterceptors方法,再调用register方法添加拦截器,前提,自定义的interceptor要加上spring注解被spring容器管理
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
}
}
总结,拦截器和过滤器的顺序
3.Aspect
在使用过滤器的时能获取request和response对象,对请求和响应进行处理,使用拦截器时,我们可以通过handler来获取当前请求控制器的方法名称。
切片编程,在网上看到了一个很贴切的说法,面对的是处理过程中的方法或者阶段,以获得各部分的低耦合性的隔离效果,它是基于动态代理,它关注的是行为和过程
@Aspect
@Component
public class TestAspect {
private Logger log = LoggerFactory.getLogger(TestAspect.class);
@Around("execution(public * com.ipark.*.modular.*.controller.*Controller.*(..))")
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("进入TestAspect切面");
Class<?> classTarget = joinPoint.getTarget().getClass();
Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
Object proceed = null;
return null;
}
}
总结,在代码里面将过滤器,拦截器,切片,还有我们常用的@ControllerAdvice异常拦截机制注解放开时,我们来看看控制台的输出
如下图
其实,当收到请求响应时,执行的顺序为filter--》interceptor--》ControllerAdvice--》Aspect,然后到达控制层,如果控制层抛出异常,最先也会被Aspect捕获,如果未处理,会继续向上一层抛出,如果到Filter也没有处理的话,就会抛到容器内部