- 通知:切面当中的方法,声明通知方法在目标业务层的执行位置,通知类型如下:
-
前置通知:@Before 在目标业务方法执行之前执行
-
后置通知:@After 在目标业务方法执行之后执行
-
返回通知:@AfterReturning 在目标业务方法返回结果之后执行
-
异常通知:@AfterThrowing 在目标业务方法抛出异常之后
-
环绕通知:@Around 功能强大,可代替以上四种通知,还可以控制目标业务方法是否执行以及何时执行
2. 代码中实现举例
===========
上面已经大概的介绍了AOP中需要了解的基本知识,也知道了AOP的好处,那怎么在代码中实现呢?给大家举个例子:我们现在有个学校管理系统,已经实现了对老师和学生的增删改,又新来个需求,说是对老师和学生的每次增删改做一个记录,到时候校长可以查看记录的列表。那么问题来了,怎么样处理是最好的解决办法呢?这里我罗列了三种解决办法,我们来看下他的优缺点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z5vx5Ual-1650705341711)(https://user-gold-cdn.xitu.io/2018/11/21/167357a2851d2cfc?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)]
-最简单的就是第一种方法,我们直接在每次的增删改的函数当中直接实现这个记录的方法,这样代码的重复度太高,耦合性太强,不建议使用。
-其次就是我们最长使用的,将记录这个方法抽离出来,其他的增删改调用这个记录函数即可,显然代码重复度降低,但是这样的调用还是没有降低耦合性。
-这个时候我们想一下AOP的定义,再想想我们的场景,其实我们就是要在不改变原来增删改的方法,给这个系统增加记录的方法,而且作用的也是一个层面的方法。这个时候我们就可以采用AOP来实现了。
我们来看下代码的具体实现:
1. 首先我定义了一个自定义注解作为切点
@Target(AnnotationTarget.FUNCTION) //注解作用的范围,这里声明为函数
@Order(Ordered.HIGHEST_PRECEDENCE) //声明注解的优先级为最高,假设有多个注解,先执行这个
annotation class Hanler(val handler: HandlerType) //自定义注解类,HandlerType是一个枚举类型,里面定义的就是学生和老师的增删改操作,在这里就不展示具体内容了
2. 接下来就是要定义切面类了
@Aspect //该注解声明这个类为一个切面类
@Component
class HandlerAspect{
@Autowired
private lateinit var handlerService: HandlerService
@AfterReturning(“@annotation(handler)”) //当有函数注释了注解,将会在函数正常返回后在执行我们定义的方法
fun hanler(hanler: Hanler) {
handlerService.add(handler.operate.value) //这里是真正执行记录的方法
}
}
3. 最后就是我们本来的业务方法了
/**
- 删除学生方法
*/
@Handler(operate= Handler.STUDENT_DELETE) //当执行到删除学生方法时,切面类就会起作用了,当学生正常删除后就会执行记录方法,我们就可以看到记录方法生成的数据
fun delete(id:String) {
studentService.delete(id)
}
3. AOP实现原理
===========
我们现在了解了代码中如何实现,那么AOP实现的原理是什么呢?之前看了一个博客说到,提到AOP大家都知道他的实现原理是动态代理,显然我之前就是不知道的,哈哈,但是相信阅读文章的你们一定是知道的。
讲到动态代理就不得不说代理模式了, 代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式包含如下角色:subject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的