java的Filter(过滤器),Interceptor(拦截器) 和 Aspect(切面)
Filter 是servlet层面的,由Servlet容器(如Tomcat)支持,只能在web程序中使用,实现了javax.servlet.Filter接口
Interceptor 是Spring Web层面的(Structs也有), 它是由Spring容器进行管理,并不依赖Tomcat等容器,既可以应用在web程序中,也可以应用在非web程序中,实现了org.springframework.web.servlet接口
Aspect 是Spring层面的,由Spring容器进行管理,有Spring的地方都可以使用
1、过滤器 (Filter) 基本用法
过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter注解实现对特定URL拦截,看到Filter 接口中定义了三个方法。
init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。注意:这个方法必须执行成功,否则过滤器会不起作用。
doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。
destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次
@Component public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter 前置"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Filter 处理中"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("Filter 后置"); } }
2、拦截器 (Interceptor) 基本用法
拦截器它是链式调用,一个应用中可以同时存在多个拦截器Interceptor, 一个请求也可以触发多个拦截器 ,而每个拦截器的调用会依据它的声明顺序依次执行。
首先编写一个简单的拦截器处理类,请求的拦截是通过HandlerInterceptor 来实现,看到HandlerInterceptor 接口中也定义了三个方法。
preHandle() :这个方法将在请求处理之前进行调用。注意:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。 有意思的是:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。
afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。
@Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Interceptor 前置"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor 处理中"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Interceptor 后置"); } }
将自定义好的拦截器处理类进行注册,并通过addPathPatterns、excludePathPatterns等属性设置需要拦截或需要排除的 URL。
@Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**"); } }
3. Aspect(切面)的基本用法
spring通知有五种类型,分别是:
前置通知(@Before):在目标方法调用之前调用通知
后置通知(@After):在目标方法完成之后调用通知
环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法
返回通知(@AfterReturning):在目标方法成功执行之后调用通知
异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知
实现
@Aspect @Component public class AopAdvice { @Pointcut("execution (* com.xxx.xxx.controller.*.*(..))") public void test() { } @Before("test()") public void beforeAdvice() { System.out.println("beforeAdvice..."); } @After("test()") public void afterAdvice() { System.out.println("afterAdvice..."); } @Around("test()") public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) { System.out.println("before"); try { proceedingJoinPoint.proceed(); } catch (Throwable t) { t.printStackTrace(); } System.out.println("after"); } }
4. Filter(过滤器),Interceptor(拦截器) 和 Aspect(切面)的区别
Filter | Interceptor | Aspect | |
原理 | 过滤器是基于函数回调 | Spring框架拦截器,基于Java反射机制 | 动态代理(jdk动态代理/cglib) |
使用范围 | web程序 | 任何程序(使用Spring) | 任何程序(使用Spring) |
拦截范围 | 对几乎所有的请求起作用 | 只对action请求起作用和static目录请求 | Spring bean |
入参 | ServletRequest, ServletResponse | HttpServletRequest , HttpServletResponse ,Object handler | ProceedingJoinPoint |
获取范围 |
可拿到原始http请求 无法获取控制器相关信息 |
可拿到控制器相关信息 拿不到方法参数 |
可拿到方法参数 拿不到http请求和响应对象 |
执行顺序
参考:
过滤器 和 拦截器的 6个区别
Filter、Interceptor、Aop实现与区别
Filter和Interceptor的联系和区别