Spring 拦截器的使用方式
基础拦截器
Spring的拦截器主要针对的是对Controller类的业务进行预处理和后处理。
Sping Framwork 5.0 以后的版本可以直接实现 HandlerInterceptor 接口,HandlerInterceptorAdapter成为一个Deprecated 类,以前的版本继承HandlerInterceptorAdapter抽象类。
HandlerInterceptor
接口有三个需要实现的方法。
-
preHandle
:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器;返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应。 -
postHandle
:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 -
afterCompletion
:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
实现步骤
- 定义一个拦截器,实现
HandlerInterceptor
接口
public class MyInterceptor implements HandlerInterceptor {
private org.slf4j.Logger log = LoggerFactory.getLogger(MyInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HandlerMethod h = (HandlerMethod) handler;
// 在这里进行
this.log.info("拦截器" + h.getBean().getClass().getName());
return true;
}
}
- 配置拦截器,实现
WebMvcConfigurer
接口的Java配置类,覆写addInterceptors
方法,添加实现的拦截器,加上匹配url的代码
@Configuration // 配置注解
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 需要注意的是,静态文件夹一定要剔除掉,例如excludePathPatterns( "/css/**", "/js/**")
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
AOP拦截器
Aspect
是更加精细化的操作,Spring Boot在使用Aspect
的时候需要加载格外的依赖Spring Boot Starter AOP
地址
/**
* 需要注意的是必须添加@Aspect、@Component这两个注解。
*/
@Aspect // 作用是把当前类标识为一个切面供容器读取
@Component // 作用是把这个类注入到spring容器
public class MyAspect {
private Logger log = LoggerFactory.getLogger(MyAspect.class);
// 定义切入点表达式
@Around("execution(* edu.uzz.demo.controller..*.*(..))")
public Object handleControllerMethods(ProceedingJoinPoint point) throws Throwable {
this.log.info("处理之前");
// 运行具体业务调用
Object obj = point.proceed(point.getArgs());
this.log.info("处理之后");
return obj;
}
}
相关注解如下:
- @Aspect:作用是把当前类标识为一个切面供容器读取
- @Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
- @Around:环绕增强,相当于MethodInterceptor
- @AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
- @Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
- @AfterThrowing:异常抛出增强,相当于ThrowsAdvice
- @After: final增强,不管是抛出异常或者正常退出都会执行
定义切入点表达式
参考文章
例如定义切入点表达式 execution (* com.sample.service.impl….(…))
execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
1、execution(): 表达式主体。
2、第一个*号:表示返回类型,号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个号:表示类名,号表示所有的类。
5、(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。