前段时间写了一个AOP的小例子,因为要在一些公共的方法前面加一个分布式的redis锁,故采用了AOP. 就是写了一个切面,切面的信息如下:
@Pointcut(value = "execution(* com.gz.eim.ac.trans.service.finance.impl.*.deal*(..))")
public void point(){
}
@Around(value = "point()")
public void around(ProceedingJoinPoint joinPoint){
String clazzName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String lockName = clazzName + "." +methodName;
logger.info("FinanceTransServiceAspect.around start, 执行类:{}.{} 方法 start, 此服务加锁的名称为:{}", clazzName, methodName, lockName);
RLock rLock = tryLock(lockName);
try {
joinPoint.proceed();
} catch (Throwable e) {
logger.error("FinanceTransServiceAspect.around error, 执行类:{}.{} 方法 start, 此服务加锁的名称为:{}, error: ", clazzName, methodName, lockName, e);
} finally {
if (rLock.isLocked()) {
rLock.unlock();
}
}
logger.info("FinanceTransServiceAspect.around end, 执行类:{}.{} 方法 end, 此服务加锁的名称为:{}", clazzName, methodName, lockName);
}
这里用到了一个切面表达式
execution(* com.gz.eim.ac.trans.service.finance.impl.*.deal*(..))
本来这里没有问题,但是我在一个deal开头的方法中设置了返回值,返回一个boolean类型,
也就是service层的这个deal开头的方法返回了一个boolean类型,但是controller层接收这个boolean类型的时候报错了:
org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public boolean com.gz.eim.ac.trans.service.finance.impl.InsuranceValueCurrentReturnReceivableServiceImpl.dealInsuranceValueCurrentReturnReceivableCurrent(java.util.Date,java.util.Date,java.util.Date,java.util.Date,java.lang.String,boolean)
上面的意思是说返回值无法转换成null,殊不知基本数据类型boolean 是不能接收null,这也是基本数据类型与包装数据类型一个很大的区别。
报错如上,查找发现 是因为 我的切面中环绕通知没有返回值,所以把真正service层的返回值吃掉了,验证得知,controller层拿不到这个返回值。
解决方案:
第一:将service层的这个boolen 基本数据类型改为 包装数据类型 Boolean
改为包装数据类型之后发现没有上面那个报错了,但是Controller层依然接受不到返回值
原因还是得看切面中的环绕通知没有处理返回值
第二:对切面中的环绕通知对返回值进行处理。
@Around(value = "point()")
public Object around(ProceedingJoinPoint joinPoint){
String clazzName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String lockName = clazzName + "." +methodName;
logger.info("FinanceTransServiceAspect.around start, 执行类:{}.{} 方法 start, 此服务加锁的名称为:{}", clazzName, methodName, lockName);
RLock rLock = tryLock(lockName);
try {
return joinPoint.proceed();
} catch (Throwable e) {
logger.error("FinanceTransServiceAspect.around error, 执行类:{}.{} 方法 start, 此服务加锁的名称为:{}, error: ", clazzName, methodName, lockName, e);
} finally {
if (rLock.isLocked()) {
rLock.unlock();
}
}
logger.info("FinanceTransServiceAspect.around end, 执行类:{}.{} 方法 end, 此服务加锁的名称为:{}", clazzName, methodName, lockName);
return null;
}
如上所示,没有再报错了,并且Controller层也能正常接收到了返回值。
那来看一下对于本身就没有返回值的deal开头的方法有没有影响,发现没有影响搞定!