1. 过滤器 和 拦截器是什么
过滤器
1. 简述:对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理。
2. 使用场景:通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理。
3. 依赖及实现:依赖Servlet,基于 [方法回调] 实现。
4. 场景:过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作。(即HTTP请求中的信息,包括request + response)
拦截器
1. 简述:拦截器,在AOP中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作,是AOP的一种实现策略。
2. 使用场景:包含了过滤器能获取到的所有信息,并能拿到 Controller的一些信息。
3. 依赖及实现:不依赖Servlet,但依赖Spring容器。
-- 网上大部分说是基于 [Java反射-动态代理] 实现,但是其实不是,只是基于责任链模式,遍历进行实现。
4. 场景:过滤器能用的场景,拦截器都能替代。能拿到Controller的一些信息。
2. 过滤器 和 拦截器区别是什么
-
来源
-- Filter
-- Interceptor
- 触发时机(位置请求的位置)
-
实现不同
// 过滤器 基于[方法回调]实现 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest request2 = (HttpServletRequest) request; System.out.println(request2.getRequestURI()); // 关键代码行 chain.doFilter(request, response); } =========================================================================================== // 拦截器 网上大部分说是基于 [Java反射-动态代理] 实现,但是其实不是,只是基于责任链模式,遍历进行实现。 Spring容器,SpringMVC中doDispatch时,会先匹配当前资源对应的所有拦截器,组成一个链式结构,循环有序调用我们重写的几个方法。 // 关键源码位置: DispatcherServlet - doDispatch - applyPreHandle / applyPostHandle -
使用场景不同
第一点: 请求顺序上,会先过Filter,再过Interceptor。 须知,资源传递是损耗性能的,那么能在开始就处理掉的,会优于在后面才处理。 所以,如果Filter能处理掉切面要完成的事情,就不要用Spring提供的Interceptor。 第二点: Spring提供的Interceptor,功能是强于Filter的。 如果存在Filter处理不了,可看Interceptor是否能完成。(前者能获取到Request\Response之外,关于Controller的一些信息)
3. 怎么使用过滤器
- 基于@WebFilter实现(缺点,不支持自定义排序)
package com.example.demo.filter;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@Component
@WebFilter(urlPatterns = "/*")
public class WebFilterTest implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器:执行 init 方法。");
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器:开始执行 doFilter 方法。");
// 请求放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("过滤器:结束执行 doFilter 方法。");
}
@Override
public void destroy() {
System.out.println("过滤器:执行 destroy 方法。");
}
}
- 基于向Spring注入FilterRegistrationBean实现(可进行排序) -- 【推荐使用】
package com.example.demo.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Configuration
public class FilterRegistrationBeanTestFilter {
@Bean
public FilterRegistrationBean<MyFilter> testFilterRegistration() {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.setName("FilterRegistrationBeanTestFilter");
// 设置执行顺序,1为最高优先级
registration.setOrder(1);
return registration;
}
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request2 = (HttpServletRequest) request;
System.out.println(request2.getRequestURI());
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
}
4. 怎么使用拦截器
拦截器使用,分两步。第一步为定义拦截器,第二步为注册拦截器。
定义拦截器:
package com.example.demo.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器:执行 preHandle 方法。");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器:执行 postHandle 方法。");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器:执行 afterCompletion 方法。");
}
}
注册拦截器
package com.example.demo.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AppConfig implements WebMvcConfigurer {
// 注入拦截器
@Autowired
private TestInterceptor testInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor)
// 拦截所有地址
.addPathPatterns("/*");
}
}
5. 总结
Java中的过滤器,以及Spring提供的拦截器,本质都是AOP思想,在请求来到的时候,在某个阶段进行预处理。
但是,过滤器所能读到的东西少一些,且两个组件处理的位置不同,所以在选用上要考虑下优先用哪个。
小tip:
1. 能用Filter处理的,优先用Filter处理。(因为资源能提前处理,在性能的角度看一般都是最佳的,这里也一样)
2. 可以写个demo,打个断点就能看到拦截器能额外拦截到的信息。
拓展:
Spring还提供了Spring AOP,其实本质上也是和上面两个组件一样的。
只是Spring AOP他处理的位置又不同了,处理上 位于 Spring提供的拦截器之后。
能获取到的也有不同,对比拦截器,能获取到传递过来参数的值,而获取不到Request/Response等信息。