Browse Source

新增注解锁支持

周浩 9 years ago
parent
commit
a585cbc5f8

+ 12 - 0
hsweb-web-concurrent/hsweb-web-concurrent-lock/pom.xml

@@ -17,5 +17,17 @@
             <artifactId>spring-boot-starter</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.webbuilder</groupId>
+            <artifactId>wb-sql-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hsweb</groupId>
+            <artifactId>hsweb-web-core</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 6 - 0
hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/ReadWriteLockFactoryAutoConfig.java

@@ -1,5 +1,6 @@
 package org.hsweb.concurrent.lock;
 
+import org.hsweb.concurrent.lock.support.AnnotationLockAopAdvice;
 import org.hsweb.concurrent.lock.support.DefaultReadWriteLockFactory;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
@@ -16,4 +17,9 @@ public class ReadWriteLockFactoryAutoConfig {
     public LockFactory createReadWriteLockFactory() {
         return new DefaultReadWriteLockFactory();
     }
+
+    @Bean
+    public AnnotationLockAopAdvice annotationLockAopAdvice() {
+        return new AnnotationLockAopAdvice();
+    }
 }

+ 140 - 0
hsweb-web-concurrent/hsweb-web-concurrent-lock/src/main/java/org/hsweb/concurrent/lock/support/AnnotationLockAopAdvice.java

@@ -0,0 +1,140 @@
+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.web.core.authorize.ExpressionScopeBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.webbuilder.utils.script.engine.DynamicScriptEngine;
+import org.webbuilder.utils.script.engine.DynamicScriptEngineFactory;
+import org.webbuilder.utils.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(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);
+            _lock.tryLock(lock.waitTime(), lock.timeUnit());
+            return pjp.proceed();
+        } finally {
+            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 lock :{} " , name);
+            readLock.tryLock(lock.waitTime(), lock.timeUnit());
+            return pjp.proceed();
+        } finally {
+            logger.debug("unlock :{} " , 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 lock :{} " , name);
+            writeLock.tryLock(lock.waitTime(), lock.timeUnit());
+            return pjp.proceed();
+        } finally {
+            logger.debug("unlock :{} " , 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);
+                if (result.getException() != null) throw result.getException();
+                lockNameStr = result.getResult().toString();
+            } else {
+                lockNameStr = lockName.value();
+            }
+        }
+        return lockNameStr;
+    }
+
+    private void unlock(Lock lock) {
+        if (lock != null) lock.unlock();
+    }
+
+}