Skip to content

Instantly share code, notes, and snippets.

@raylax
Created March 26, 2019 05:50
Show Gist options
  • Save raylax/b28fcaf2bd31c6344dab032687bf8256 to your computer and use it in GitHub Desktop.
Save raylax/b28fcaf2bd31c6344dab032687bf8256 to your computer and use it in GitHub Desktop.
package com.jjl.features.lock;
import com.jjl.features.exception.ConcurrentException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ConcurrentModificationException;
/**
* 分布式锁Aspect
* @author raylax
*/
@Slf4j
@Aspect
@Component
public class LockAspect {
@Autowired
private DistributedLock distributedLock;
private static final String LOCK_PREFIX = "aspect.lock:";
private final ExpressionParser parser = new SpelExpressionParser();
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
@Around("@annotation(com.jjl.features.lock.Lock)")
public Object doAroundMethod(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
Lock lock = method.getAnnotation(Lock.class);
EvaluationContext context = new MethodBasedEvaluationContext(
null, method, pjp.getArgs(), paramNameDiscoverer);
Boolean when = parser.parseExpression(lock.when()).getValue(context, Boolean.class);
if (when == null || !when) {
return pjp.proceed(pjp.getArgs());
}
String name = LOCK_PREFIX + parser.parseExpression(lock.name()).getValue(context, String.class);
if (!distributedLock.tryLock(name, lock.expire())) {
log.info("failed to lock resource [{}]", name);
throw new ConcurrentException();
}
log.info("resource [{}] locked", name);
try {
return pjp.proceed();
} finally {
distributedLock.release(name);
log.info("resource [{}] released", name);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment