Spring Boot入坑-4-AOP、Interceptor和Filter
概述
-
面向切面编程(Aspect Oriented Programming),从不同的维度或角度给已有程序添加附加功能的一种技术
-
实现的方式是Spring容器为程序创建代理,让调用方无感知的调用指定方法,在运行期间动态的“织入”其他逻辑
-
主要目的是为了解耦
-
弥补OOP中只能继承类或实现接口进行功能扩充的不足
-
让应用逻辑更加清晰,业务逻辑只关注业务本身
-
可以获取拦截方法请求的参数和返回,但不能获取HTTP信息
-
主要应用场景:声明式事务、服务权限过滤、缓存、全局日志和一些框架的持久化
主要注解
-
@Aspect:定义一个切面
-
@Pointcut(value=“表达式标签”):定义切入点,可以指定相应的包、类、注解做为切入点,有12种表达式标签,常用的为execution(表达式),表达式又支持很多种格式
-
@Before:切入点方法执行前调用
-
@After:切入点方法执行后调用
-
@AfterReturning:切入点方法正常执行并成功返回后调用
-
@AfterThrowing:切入点方法产生并抛出异常后调用
-
@Around:切入点方法环绕处理,完全控制方法是否执行,能在方法执行前、执行后添加相应的逻辑,可以理解为包含上述所有逻辑
常用的表达式标签
-
execution:匹配方法执行的连接点
-
within:匹配指定类型内的方法执行
-
this:匹配当前AOP代理对象类型的执行方法
-
target:匹配当前目标对象类型的执行方法
-
args:匹配当前执行的方法传入的参数为指定类型的执行方法
-
@within:匹配所以持有指定注解类型内的方法
-
@target:匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解
-
@args:匹配当前执行的方法传入的参数持有指定注解的执行
-
@annotation:匹配当前执行方法持有指定注解的方法
-
bean:Spring AOP扩展的,匹配特定名称的Bean对象的执行方法
注意:了解即可,不需要记住,有业务需要的时候,再去看详细的内容
execution表达式
-
execution包含的表达式,支持各种格式,了解常用的就好,使用时根据业务需要再去学习相应的匹配模式
-
常用的匹配通配符有
-
*:匹配任何数量字符
-
..:匹配任何数量的子包,或方法中的任意多个参数
-
+:匹配指定类型及子类型
-
-
execution匹配示例
-
public * *.*(..):匹配任意公共方法
-
* com.example.service.UserService.*():匹配com.example.serviceUserSerivce下的所有无参方法,返回值类型任意
-
* com.example.service.service.UserService.getById(..):匹配userService.getById方法,传入参数任意,返回值任意
-
使用步骤
-
添加依赖:在pom.xml中添加对spring-boot-starter-aop的依赖
<!--【AOP】1、添加依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
定义切面:定义一个类,使用@Aspect注解修饰,
-
定义切入点:在类中添加一个方法,使用@Pointcut注解修饰成切入点
-
进行拦截:在类中添加一个方法,使用@Around(“切入点注解的方法名”)等注解实现拦截;可以在相应方法中进行权限判断、日志记录等工作
-
概述
-
是一个Controller增强器,也一个Component
-
主要实现全局的控制器拦截处理
-
多用于通用异常处理
主要作用
-
通过给定义的控制器类添加@ControllerAdvice注解,对控制器进行拦截
-
常用的方式有
-
全局异常处理,配合@ExceptionHandler注解,对通用异常统一捕获处理
-
全局数据绑定,配合@ModelAttribute注解,可以添加一些全局数据,这些数据可以在任意Controller中进行访问,较少使用
-
全局数据预处理,配合@InitBinder、@ModelAttribute注解,可以对一些传递进入的数据进行一些预处理,较少使用
-
全局异常处理使用步骤
-
添加指定异常处理方法,结合@ControllerAdvice注解和@@ExceptionHandler实现
-
查看效果,在@Controller的服务中抛出指定异常查看
【示例】
-
@ControllerAdvice注解的使用,见附件项目springboot-advice项目
-
全局异常处理,advice\GlobalExceptionHandler类
-
全局数据绑定,advice\GlobalDataHandler类
-
-
概述
-
拦截器,基于SpringMVC,能对控制器(@Controller注解标识的类)中的服务方法(Action,使用@xxxMapping注解标识的方法)访问前后进行拦截
-
一般不能拦截静态资源、页面等其他web相关的其他内容
-
主要应用场景有:日志记录、权限检查、性能监控等,项目可以使用Interceptor进行身份认证与授权处理
使用步骤
-
自定义拦截器
-
实现HandlerInterceptor接口
-
添加@Component注解
-
覆写接口的三个方法
-
preHandle:方法被处理之前调用,如果返回false,则中断方法的调用
-
postHandle:方法被处理没有异常后调用
-
afterCompletion:方法被处理之后调用,不管是否有异常
-
-
-
注册拦截器
-
自定义Web拦截类,实现WebMvcConfigurer接口,一个Spring Boot项目一般只有一个Web拦截
-
覆盖addInterceptors方法,在其中将需要拦截的URL关联到自定义的拦截器
-
-
查看效果,自动生效,通过断点或日志,查看注册拦截器针对Action的拦截效果
【示例】
概述
-
过滤器,是属于Servlet规范中的功能
-
能对所有的Web请求进行过滤,包括静态资源和页面
-
能配置多个过滤器组成一个过滤器链
-
主要应用场景:字符编码转换,敏感词过滤、登陆权限验证、资源访问权限等,尤其是带页面或静态资源的Web页面
-
具体过程如下图
Filter过滤过程图 使用步骤
-
自定义过滤器
-
实现Filter接口
-
覆写doFilter过滤方法,同时也可以对init初始方法、destroy销毁方法进行定义
-
给自定义类添加@WebFilter注解,通过urlPatterns指定过滤的URL匹配模式
-
存在多个过滤器时,可以通过@Order注解定义过滤的先后顺序
-
-
注册过滤器
-
在main方法所在的启动类,添加@ServletComponentScan注解
-
-
查看效果,自动生效,通过断点或日志,查看注册过滤器的拦截效果
-
【示例】
-
AOP、@ControllerAdvice、Interceptor、Filter都能起到拦截(过滤)的作用
-
相比来说,在拦截(过滤)的先后顺序、相应的特点还有有些差异
-
拦截(过滤)顺序如下图
拦截(过滤)顺序图 -
特点对比如下图
特点对比
Servlet简介
-
Servlet是基于Java技术的Web组件
-
是运行于服务器端的Java程序,能够接受客户端发起的HTTP请求并动态地生成页面内容
-
Spring Boot中对于@Controller的请求,都是通过SpringMVC的DispatcherServlet进行分发
-
传统的JSP页面,本质上也是Servlet
【示例】
概述
-
在一个完整的Web应用运行中,会存在应用、会话、请求/响应等多个专业的术语(功能)
-
理解好这些术语(功能),能更好的理解Web应用
-
这此术语(功能)有
-
Application
-
应用,一个Web应用一启动,就会产生一个全局的对象,就是Application
-
相当于全局变量,往其中添加的数据也叫全局数据
-
在应用中,任意用户、在任意位置到可以获取或设置Application中的数据
-
比如存放像站点当前在线人数等数据
-
-
Session
-
会话,由于HTTP协议的无状态特性,Web应用并不能识别同一个浏览器用户的连续多次访问是否为同一个用户
-
如何让Web应用记住并识别同一个浏览器用户在一个指定时间内的多次访问是同一个用户,是很重要的,这就要用到Session,也叫会话
-
一个Spring的Web应用会为每一个浏览器用户维持一个指定时长的Session,里面可以存放数据;浏览器用户可以在其中任意一次连接过程中存储或访问Session中的数据
-
这个指定时长默认是30分钟,可通过server.servlet.session.timeout配置;如server.servlet.session.timeout=1m,表示会话超时时间为1分钟
-
Session中一般存放会话期浏览器用户的身份验证数据、公共数据等信息
-
-
Request
-
请求,浏览器用户的一次请求,就称之为Request
-
-
Response
-
响应,如果Web应用能完整的处理请求,会给请求方发送一个响应,即Response
-
-
如何使用
-
在Java中,分别是通过ServletContext(Application)、HttpSession(Session)、HttpServletRequest(Request)、HttpServletResponse(Response)来实现上述功能
-
其中
-
ServletContext、HttpSession对象已经在启动时注入到容器,可以直接装配使用
-
HttpServletRequest、HttpServletResponse则要在控制器的Action添加HttpServletRequest、HttpServletResponse参数进行使用,比如获取请求头
-
【示例】
-
常见的业务场景
-
也有比较多的针对图片,且上传后需要显示
-
可以配置限制上传文件的大小
#总上传请求 spring.servlet.multipart.max-request-size=100MB #单个文件大小 spring.servlet.multipart.max-file-size=10MB
-
注意
-
上传文件一般要限定文件扩展名,比如不能是.js、.class、.py、.jsp等,能做内容限定更好
-
文件上传后,上传的目录一般的情况下要做为能直接访问的Web目录,防止上传执行漏洞
-
【示例】
代码