12

Spring AOP在项目中的典型应用场景

 2 years ago
source link: http://www.javaboy.org/2022/1208/spring-aop.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
12 天前 14 分钟 读完 (大约 2170 个字)

Spring AOP在项目中的典型应用场景

学过 Spring 的小伙伴相信都知道 AOP,AOP 学的好的小伙伴相信对 AOP 的概念也是轻车熟路:面向切面编程、切点、切面、通知,Aspect、Pointcut、Advice 等如数家珍。

AOP 之所以这么重要,是因为它在项目中有着非常广泛的应用,今天这篇文章,松哥就来和大家总结一下,我们在日常开发中,都有哪些典型场景需要用到 AOP。

先来一句话总结下,AOP 的使用,基本上都会涉及到自定义注解,一个非常常见的组合,就是自定义注解+AOP。

在日常的开发中,有很多重复的代码,我们总是希望将之简化,AOP 就是一个非常常用的简化手段。简化的思路一般是这样:

  1. 首先,自定义一个注解。
  2. 定义 AOP 切面,在切面中,定义切点和通知,切点,也就是方法的拦截规则,我们可以按照注解来拦截,也就是某一个带有自定义注解的方法,将被我拦截下来。
  3. 拦截下来之后,前置通知、后置通知、异常通知、返回通知还是环绕通知,就可以随便写了。

所以,这些涉及到自定义注解的地方,基本上都可以算是 AOP 的使用场景了,因为自定义注解,需要用 AOP 来解析。

接下来我们来看几个比较典型的例子。

1. 幂等性处理

接口幂等性的处理,其实有很多种不同的方案,例如:

  1. Token 机制
  2. 利用 Redis 的 setnx
  3. 设置状态字段

无论是哪种方案处理幂等性,每个方法里边都去写一遍幂等性的处理显然是不现实的,因此,一般都是将幂等性的处理通过自定义注解+AOP给封装起来,大致的思路如下:

  1. 首先自定义一个注解。
  2. 自定义切点,拦截所有加了自定义注解的方法。
  3. 定义环绕通知,在环绕通知中,先通过上述五种思路中的任意一种,对方法执行的幂等性进行判断,判断通过了,再执行目标方法,判断不通过,则直接抛出异常,不执行目标方法。

这就是自定义注解+AOP 的一个典型应用场景。

如果你对上面的表述云里雾里,不妨看看松哥之前发的这个视频,有详细的手把手教程:处理接口幂等性的两种常见方案|手把手教你

2. 接口限流

对于接口限流,目前来说,一个比较成熟的方案是使用 Alibaba 的 Sentienl,简单配置一下就可以实现接口限流了。

但是如果没有用这个工具呢?如果是我们自己写呢?毫无疑问,还是自定义注解+AOP,思路大致如下:

  1. 自定义注解。
  2. 在需要进行限流的接口方法上添加自定义注解,同时还可以设置一些限流的参数,例如时间窗口值、流量大小等。
  3. 自定义切点,拦截规则就是所有添加了自定义注解的方法,拦截到方法之后,在环绕通知中,可以通过 Redis 插件 redis-cell、通过漏斗算法去处理限流,这个我这里就不罗嗦了,之前的文章中都写过了。限流计算没问题的话,就执行目标方法,否则将操作拦截下来。

大致思路如上,说白了就是自定义注解+ AOP,道理虽然简单,但是真正做起来,还是有很多细节,感兴趣的小伙伴可以参考松哥之前的这篇文章:Redis 做接口限流,一个注解的事!

3. 日志处理

说到 AOP,所有人都能想到的使用场景了,这个我就不罗嗦了,松哥之前也有过专门的文章介绍,没看过的小伙伴们戳这里:记录项目日志,一个注解搞定

4. 多数据源处理

有时候我们项目中存在多个不同的数据源,在实际使用中需要进行切换,网上也有一些开源的解决方案,不过这个东西其实并不难,我们也可以自己写。

自定义多数据源的处理,大致上思路如下:

从 Spring2.0.1 中引入了 AbstractRoutingDataSource 类,(注意是 Spring2.0.1 不是 Spring Boot2.0.1,所以这其实也算是 Spring 一个非常古老的特性了), 该类充当了 DataSource 的路由中介,它能够在运行时, 根据某种 key 值来动态切换到真正的 DataSource 上。

大致的用法就是你提前准备好各种数据源,存入到一个 Map 中,Map 的 key 就是这个数据源的名字,Map 的 value 就是这个具体的数据源,然后再把这个 Map 配置到 AbstractRoutingDataSource 中,最后,每次执行数据库查询的时候,拿一个 key 出来,AbstractRoutingDataSource 会找到具体的数据源去执行这次数据库操作。

基于以上知识,我们可以自定义一个注解,在需要切换数据源的方法上,添加这个注解,然后通过 AOP 去解析这个自定义注解,当目标方法被拦截下来的时候,我们跟进注解中的配置,重新设置要执行的数据源,这样将来 service 中的方法在执行的过程中,就会使用到切换之后的数据源了。

思路并不难,松哥之前也写过详细的教程,小伙伴们参考这里:

5. 方法权限处理

这个其实也跟前面的差不多。

方法级别的权限处理,一般来说也是基于注解来完成的。如果你使用了 Spring Security 之类的权限框架,就不用自己解析权限注解了,按照框架的要求直接来使用就行了。

有的时候,我们可能没有使用 Spring Security,想自己处理权限注解,也是可以的。用户自定义权限注解,为注解添加属性,然后将注解添加到目标方法上,再通过 AOP 去解析这个注解,AOP 将目标方法的执行拦截下来,然后判断用户是否具备所需要的权限,如果具备,就执行目标方法,否则就不执行。

前两天松哥刚刚分享的在微服务中,服务内部的权限校验,就是自定义一个注解,将从其他微服务上来的请求给拦截下来,然后判断请求的来源,如果是从其他微服务上来的,就执行目标方法,如果不是从其他微服务上来的,而是从外部来的请求,那么就将之拦截下来抛出异常,不执行目标方法,参见:微服务中的鉴权该怎么做?

6. 事务处理

这个倒是不需要自定义注解,对于声明式事务,直接用现成的注解就行了,但是本质上也是 AOP,如果有小伙伴在 Spring 的 XML 中配置过事务的话,就知道这个东西底层也是 AOP。

好啦,梳理了几个简单的案例,希望小伙伴们了解到 AOP 并不是屠龙术,而是在日常开发中有着广泛应用的技术。

# Spring

喜欢这篇文章吗?扫码关注公众号【江南一点雨】【江南一点雨】专注于 SPRING BOOT+微服务以及前后端分离技术,每天推送原创技术干货,关注后回复 JAVA,领取松哥为你精心准备的 JAVA 干货!

javaboy.jpg

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK