AOP实战
一、定义AOP切面
package com.aop.service;
import com.alibaba.fastjson.JSONObject;
import com.tf56.core.BizReturn;
import com.tf56.core.exception.BizError;
import com.tf56.hermesContract.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.lang.reflect.Method;
@Component
@Aspect
@Slf4j
public class AopAspectService {
@Pointcut("execution(* com.aop.service.impl.*.*(..))")
private void pointcut() {
log.info("pointcut");
}
/**
* 调用服务前对入参进行入参记录
* @param joinPoint
*/
@Before(value = "pointcut()")
public void before(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
StringBuilder str = new StringBuilder();
str.append("before: ")
.append(className)
.append("@")
.append(methodName)
.append(" , params: ");
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
str.append(JSONObject.toJSONString(arg) + ", ");
}
log.info(str.toString());
}
@AfterReturning(value = "pointcut()", returning = "returnObj")
public void afterReturn(Object returnObj) {
String res = JSONObject.toJSONString(returnObj);
log.info("afterReturning: " + (res.length() > 2000 ? res.substring(0, 2000) + "......" : res));
}
@AfterThrowing(value = "pointcut()", throwing = "e")
public void afterThrowing(Throwable e) {
log.error("afterThrowing: " + e.getMessage(), e);
}
@Around(value = "pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Long begin = System.currentTimeMillis();
StringBuilder str = new StringBuilder("around: ");
Object result = null;
try {
result = proceedingJoinPoint.proceed();
} catch (BusinessException bse) {
log.error(str + bse.getMessage(), bse);
if (checkTransactional(proceedingJoinPoint)) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return BizReturn.createError(new BizError(bse.getErrorCode(), bse.getMessage(), null));
} catch (RuntimeException e) {
log.error(str + e.getMessage(), e);
if (checkTransactional(proceedingJoinPoint)) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return BizReturn.createError(e.getMessage());
}
Long end = System.currentTimeMillis();
str.append(" 执行时间: ").append(end - begin).append("ms");
log.info(str.toString()); // 记录接口执行时间
return result;
}
/**
* 判断是否有事务注解
* @param proceedingJoinPoint
* @return
*/
private boolean checkTransactional(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException {
Signature signature = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method realMethod = proceedingJoinPoint.getTarget().getClass()
.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
return realMethod.isAnnotationPresent(Transactional.class);
}
}
二、接口及实现
package com.aop.service;
public interface AopService {
BizReturn create(); // 所有借口返回BizReturn,自定义,可以定义成其他的,根据需要在AOP中捕获自定义异常,处理已定义异常,回滚事务
}
package com.aop.service.impl;
import com.aop.service.AopService;
import com.tf56.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("aopService")
@Slf4j
public class AopServiceImpl implements AopService {
@Override
@Transactional
public BizReturn create() {
log.info("create start.");
throw new BizException("数据不存在...");
}
}
三、单测使用示例
@Autowired
private AopService aopService;
@Test
public void createTest() {
String s = aopService.create();
}