package org.hsweb.concurrent.lock.support; 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.hsweb.concurrent.lock.LockFactory; import org.hsweb.concurrent.lock.annotation.LockName; import org.hsweb.concurrent.lock.exception.LockException; import org.hsweb.web.core.authorize.ExpressionScopeBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.hsweb.expands.script.engine.DynamicScriptEngine; import org.hsweb.expands.script.engine.DynamicScriptEngineFactory; import org.hsweb.expands.script.engine.ExecuteResult; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; /** * Created by zhouhao on 16-5-13. */ @Aspect public class AnnotationLockAopAdvice { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private LockFactory lockFactory; private ConcurrentMap<String, Lock> lockMap = new ConcurrentHashMap<>(); private ConcurrentMap<String, ReadWriteLock> readWriteLockMap = new ConcurrentHashMap<>(); @Autowired(required = false) private Map<String, ExpressionScopeBean> expressionScopeBeanMap; @Around("@annotation(unLock)") public Object unWriteLock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.UnWriteLock unLock) throws Throwable { String name = getLockName(pjp); ReadWriteLock lock = readWriteLockMap.get(name); try { return pjp.proceed(); } finally { logger.debug("unlock :{}", name); if (lock != null) unlock(lock.writeLock()); } } @Around("@annotation(unLock)") public Object unReadLock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.UnReadLock unLock) throws Throwable { String name = getLockName(pjp); ReadWriteLock lock = readWriteLockMap.get(name); try { return pjp.proceed(); } finally { logger.debug("unlock :{}", name); if (lock != null) unlock(lock.readLock()); } } @Around("@annotation(unLock)") public Object unlock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.UnLock unLock) throws Throwable { String name = getLockName(pjp); Lock lock = lockMap.get(name); try { return pjp.proceed(); } finally { logger.debug("unlock :{}", name); unlock(lock); } } @Around("@annotation(lock)") public Object lock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.Lock lock) throws Throwable { String name = getLockName(pjp); Lock _lock = lockMap.get(name); if (_lock == null) { synchronized (lockMap) { lockMap.put(name, _lock = lockFactory.createLock(name)); } } try { logger.debug("try lock :{}", name); boolean locked = _lock.tryLock(lock.waitTime(), lock.timeUnit()); if (!locked) throw new LockException(name + "error"); return pjp.proceed(); } finally { if (lock.autoUnLock()) { logger.debug("unlock :{}", name); unlock(_lock); } } } @Around("@annotation(lock)") public Object readLock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.ReadLock lock) throws Throwable { String name = getLockName(pjp); ReadWriteLock readWriteLock = readWriteLockMap.get(name); if (readWriteLock == null) { synchronized (readWriteLockMap) { readWriteLockMap.put(name, readWriteLock = lockFactory.createReadWriteLock(name)); } } Lock readLock = readWriteLock.readLock(); try { logger.debug("try readLock :{} ", name); boolean locked = readLock.tryLock(lock.waitTime(), lock.timeUnit()); if (!locked) throw new LockException(name + "error"); return pjp.proceed(); } finally { if (lock.autoUnLock()) { logger.debug("unlock readLock :{} ", name); unlock(readLock); } } } @Around("@annotation(lock)") public Object writeLock(ProceedingJoinPoint pjp, org.hsweb.concurrent.lock.annotation.WriteLock lock) throws Throwable { String name = getLockName(pjp); ReadWriteLock readWriteLock = readWriteLockMap.get(name); if (readWriteLock == null) { synchronized (readWriteLockMap) { readWriteLockMap.put(name, readWriteLock = lockFactory.createReadWriteLock(name)); } } Lock writeLock = readWriteLock.writeLock(); try { logger.debug("try writeLock :{} ", name); boolean locked = writeLock.tryLock(lock.waitTime(), lock.timeUnit()); if (!locked) throw new LockException(name + "error"); return pjp.proceed(); } finally { if (lock.autoUnLock()) { logger.debug("unlock writeLock:{} ", name); unlock(writeLock); } } } public String getLockName(ProceedingJoinPoint pjp) throws Throwable { String lockNameStr; MethodSignature methodSignature = ((MethodSignature) pjp.getSignature()); LockName lockName = methodSignature.getMethod().getAnnotation(LockName.class); if (lockName == null) lockName = pjp.getTarget().getClass().getAnnotation(LockName.class); if (lockName == null) { lockNameStr = pjp.getTarget().getClass().getName(); } else { if (lockName.isExpression()) { String expression = lockName.value(); String expressionId = String.valueOf(expression.hashCode()); DynamicScriptEngine engine = DynamicScriptEngineFactory.getEngine(lockName.expressionLanguage()); boolean compiled = engine.compiled(expressionId); if (!compiled) { engine.compile(expressionId, expression); } Map<String, Object> var = new HashMap<>(); String paramNames[] = methodSignature.getParameterNames(); for (int i = 0; i < paramNames.length; i++) { var.put(paramNames[i], pjp.getArgs()[i]); } if (expressionScopeBeanMap != null) var.putAll(expressionScopeBeanMap); ExecuteResult result = engine.execute(expressionId, var); lockNameStr = (String) result.getIfSuccess(); } else { lockNameStr = lockName.value(); } } return lockNameStr; } private void unlock(Lock lock) { if (lock != null) { try { lock.unlock(); } catch (Throwable e) { logger.error("unlock error", e); } } } }