最近,有个项目需要完成一个功能,每当数据改变时(简单来说就是对数据进行增删改操作),需要将改变的数据传给其他模块。
对于该功能的实现,我思考了两种方式:
第一种就是最简单但又最麻烦的方式:在每个增删改方法下增加传递数据的代码。该方式需要在每个方法上增加,比较麻烦而且不易维护,所以自己并没有采用。
第二种是使用监听的方式实现。对于能实现监听的方式有多种,但有些实现方式如果要实现监听,需要继承专门的监听类,但是对于这一类监听类都不熟悉,所以最后选择了使用aop的方式实现。
使用aop实现方法监听
具体操作:
定义一个aop类
@Slf4j
@Component
@Aspect
@Transactional(rollbackFor = Exception.class)
public class AopExample{
@Before("execution(* com.example.ExampleClass.delete*(..))")
public void handleCashBefore(JoinPoint jp) {
// 获取执行的方法名
String s = jp.toShortString();
// 字符串处理,获取方法名
String methodName = strAddress(s);
// 获取目标方法体参数
Object[] args = jp.getArgs();
// todo 具体的实现方法
}
}
如上代码所示,定义AopExample类,在该类上加上@Component
@Aspect注解即可。
然后在类中定义一个方法,在方法上加上@Before、@After等注解。关于每个注解的含义可自行百度,这里就不细说了。每个注解里需要给定监听的方法,例如"execution(* com.example.ExampleClass.delete*(…))",表示监听ExampleClass这个类里以delete开头的所有方法。如果只想监听某一个,则将*替换成对应的名字即可。JoinPoint 能获取到关于该方法的一些信息,比如能获取到参数值、方法名等。
但是,我需要监听的不仅仅是删除方法,还有增加和修改方法。所以需要增加几个方法来实现。
@Pointcut(value = "execution(* com.example.ExampleClass.update*(..))")
public void updateHandleCache() {
// Do nothing
}
@Pointcut(value = "execution(* com.example.ExampleClass.save*(..))")
public void saveHandleCache() {
// Do nothing
}
@AfterReturning(pointcut = "updateHandleCache() || saveHandleCache()")
public void handleCashAfterReturning(JoinPoint jp) {
// 获取执行的方法名
String s = jp.toShortString();
// 字符串处理,获取方法名
String methodName = strAddress(s);
// 获取目标方法体参数
Object[] args = jp.getArgs();
}
如果方法实现的功能类似的话,我觉得尽量将方法的命名统一,对于有时突然增加的功能,会有益处。就像我这次遇到的,如果方法名不统一,使用aop的话,还要修改方法名,增加工作量。那为何不在一开始就统一呢?