Spring Boot是很优秀的框架,它的出现简化了新Spring应用的初始搭建以及开发过程,大大减少了代码量,目前已被大多数企业认可和使用。这个专栏将对Spring Boot框架从浅入深,从实战到进阶,不但我们要懂得如何去使用,还要去剖析框架源码,学习其优秀的设计思想。
汇总目录链接:【Spring Boot实战与进阶】学习目录
文章目录- 一、过滤器
- 二、拦截器
- 三、过滤器和拦截器的区别
一、过滤器
过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改。也可以对响应进行过滤,拦截或修改响应。
1、自定义一个TimeFilter类
代码语言:javascript复制@Component
@WebFilter(urlPatterns = {"/*"})
public class TimeFilter implements Filter{
Logger log = LoggerFactory.getLogger(Logger.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("【过滤器】初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("【过滤器】开始执行");
Long startTime = System.currentTimeMillis();
filterChain.doFilter(servletRequest, servletResponse);
log.info("【过滤器】耗时:" (System.currentTimeMillis() - startTime) "ms");
log.info("【过滤器】结束执行");
}
@Override
public void destroy() {
log.info("【过滤器】销毁");
}
}
2、配置方式
- @WebFilter注解的urlPatterns属性配置了哪些请求可以进入该过滤器,/*表示所有请求。
- 除了在过滤器类上加注解外,我们也可以通过FilterRegistrationBean来注册过滤器。定义一个TimeFilterConfig类,加上@Configuration注解表明其为配置类,然后通过FilterRegistrationBean来注册过滤器。
public class TimeFilterConfig {
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
filterRegistrationBean.setFilter(timeFilter);
List<String> urlList = new ArrayList<>();
urlList.add("/*");
filterRegistrationBean.setUrlPatterns(urlList);
return filterRegistrationBean;
}
}
3、项目演示
代码语言:javascript复制@RestController
public class HelloController {
Logger log = LoggerFactory.getLogger(Logger.class);
@RequestMapping("hello")
public void hello(){
log.info("Controller:Hello World!");
}
}
启动项目,可以在控制台看到输出了过滤器初始化,访问http://localhost:8080/hello
控制台输出
代码语言:javascript复制【过滤器】开始执行
Controller:Hello World!
【过滤器】耗时:26ms
【过滤器】结束执行
二、拦截器
拦截器,是面向切面编程(AOP,Aspect Oriented Program)的。就是在Service或者一个方法前调用一个方法,或者在方法后调用一个方法。比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。
1、定义一个TimeInterceptor类
代码语言:javascript复制@Component
public class TimeInterceptor implements HandlerInterceptor {
Logger log = LoggerFactory.getLogger(Logger.class);
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
log.info("【拦截器】处理前");
httpServletRequest.setAttribute("startTime", System.currentTimeMillis());
log.info(((HandlerMethod) o).getBean().getClass().getName());
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
log.info("【拦截器】处理中");
Long start = (Long) httpServletRequest.getAttribute("startTime");
log.info("【拦截器】耗时:" (System.currentTimeMillis() - start) "ms");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
log.info("【拦截器】处理后");
Long start = (Long) httpServletRequest.getAttribute("startTime");
log.info("【拦截器】耗时:" (System.currentTimeMillis() - start) "ms");
}
}
2、在TimeInterceptorConfig中通过InterceptorRegistry注册过滤器。
代码语言:javascript复制@Configuration
public class TimeInterceptorConfig extends WebMvcConfigurerAdapter {
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
3、项目演示
代码语言:javascript复制@RestController
public class HelloController {
Logger log = LoggerFactory.getLogger(Logger.class);
@RequestMapping("hello")
public void hello(){
log.info("Controller:Hello World!");
}
}
启动项目,访问http://localhost:8080/hello
控制台输出
代码语言:javascript复制【拦截器】处理前
com.boot.filter.controller.HelloController
Controller:Hello World!
【拦截器】处理中
【拦截器】耗时:22ms
【拦截器】处理后
【拦截器】耗时:22ms
三、过滤器和拦截器的区别
主要区别: 1、拦截器是基于Java的反射机制的,而过滤器是基于函数回调。 2、拦截器不依赖于servlet容器,过滤器依赖于servlet容器。 3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。 4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。 5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次 6、拦截器可以获取IOC容器中的各个bean(基于FactoryBean接口 ),而过滤器就不行,在拦截器里注入一个service,可以调用业务逻辑。
本质区别: 从灵活性上说拦截器功能更强大些,Filter能做的事情它都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验,其他的还是建议用interceptor。
执行顺序:
代码语言:javascript复制【过滤器】开始执行
【拦截器】处理前
com.boot.filter.controller.HelloController
Controller:Hello World!
【拦截器】处理中
【拦截器】耗时:20ms
【拦截器】处理后
【拦截器】耗时:20ms
【过滤器】耗时:27ms
【过滤器】结束执行
过滤前-----拦截前-----Action处理-----拦截后-----过滤后。