1 定义 PointCut 连接点注解类
/**
* DB 锁
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) //表示该注解只能用在方法上
public @interface DbLock {
public BusiType type(); // 锁定的类型
public String[] key() default {}; // 锁的值,只能用在第一个参数上
}
2 定义切面类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
/**
* DB 锁工具
*/
@Aspect
@Component
public class DbLockInterceptor {
@Autowired
private DbLockService dbLockService;
/**
* DB lock,在任务执行的过程中加锁, 如果没有争取到锁, 则不执行
*
* @param pjp
* @return
* @throws Throwable
*/
//定义@Around增强,poincut连接点使用@annotation(xxxx)进行定义
@Around("@annotation(dbLockParam)")
public Object processTx(ProceedingJoinPoint pjp, DbLock dbLockParam) throws Throwable {
boolean needReleaseDbLock = dbLockParam.type().isNeedReleaseDbLock(); // 是否要释放锁标志
String[] keys = dbLockParam.key(); // 额外参数
Object[] arguments = pjp.getArgs();
String lockValue = "";
if (keys.length > 0) { // 存在keys的,根据第一个参数,创建lockValue
Object targetKey = arguments[0];
for (String key : keys) {
Field field = ReflectionUtils.findField(targetKey.getClass(), key);
ReflectionUtils.makeAccessible(field);
targetKey = ReflectionUtils.getField(field, targetKey);
}
lockValue = targetKey.toString();
} else {
for (Object argument : arguments) {
lockValue += argument.toString() + "_";
}
}
DbLockDto lockObj = getLock(dbLockParam.type(), lockValue);
if(lockObj == null){
// not get lock
Logger.info(this, "type = ["+dbLockParam.type()+"] with lockValue = ["+lockValue+"] not get lock");
return null;
}else{
Logger.info(this, "type = ["+dbLockParam.type()+"] with lockValue = ["+lockValue+"] get lock");
}
Object result = null;
try {
result = pjp.proceed();
} finally {
if (needReleaseDbLock) {
boolean releaseResult = dbLockService.tryRelease(lockObj.getId());
if (releaseResult) {
Logger.info(this, "type = ["+dbLockParam.type()+"] with lockValue = ["+lockValue+"] release lock");
}else{
Logger.info(this, "type = ["+dbLockParam.type()+"] with lockValue = ["+lockValue+"] release lock fail");
}
}else{
Logger.info(this, "type = ["+dbLockParam.type()+"] with lockValue = ["+lockValue+"] not release lock");
}
}
return result;
}
private DbLockDto getLock(BusiType type, String value){
DbLockDto lockObj = dbLockService.queryDbLock(type, value);
if (lockObj == null) {
lockObj = dbLockService.saveDbLock(type, value);
if (lockObj == null) {
// no lockObj created
return null;
} else {
// OK, get Lock
return lockObj;
}
} else {
if (DBLockConstants.LOCK.equals(lockObj.getIsLock())) {
// no lockObj get,
return null;
} else {
boolean getLockStatus = dbLockService.tryLock(lockObj.getId());
if (getLockStatus) {
// OK, get Lock
return lockObj;
} else {
return null;
}
}
}
}
}
切面类 详解
- @Aspect 注解类 定义切面类
- @Around(value="@annotation(around)") 注解增强的代理方法,指定pointcut连接点 参数around应该与增强处理方法中的参数名保持一致
- result = pjp.proceed(); //调用目标方法
- 该切面类的实现放重 是基于wmc_trd_db_lock 表中添加了 唯一索引(type+value 组合索引)
3 为待增强的方法--添加注解申明
需要对某一方法增强加@DbLock注解
// 记录订单 关键字trxId
@DbLock(type = BusiType.OrderReceive, key = {"investTraceInfo", "sid"})
public ProductMultipleTrxDto saveOrder(InvestConditionInfo investInfo) {
ProductMultipleTrxDto order = new ProductMultipleTrxDto(investInfo);
productMultipleTrxDAO.save(order);
investInfo.getInvestTraceInfo().setTrxId(order.getId());
return order;
}
4 AspectJ配置文件
<context:component-scan base-package="com.xxxx"/>
<aop:aspectj-autoproxy />
参考:https://www.cnblogs.com/ssslinppp/p/5845659.html