danchaofan1412 5 éve
szülő
commit
c0f0634912

+ 33 - 0
framework-starter/mrxu-starter-redisson/pom.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.mrxu</groupId>
+        <artifactId>mrxu-upgrader</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>com.mrxu</groupId>
+    <artifactId>mrxu-starter-redisson</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>mrxu-starter-redisson</name>
+    <description>mrxu starter</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.mrxu</groupId>
+            <artifactId>framework-boot</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.11.3</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 96 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/RedisCache.java

@@ -0,0 +1,96 @@
+package com.mrxu.framework.starter.redisson;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+import org.redisson.api.RMapCache;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+import lombok.RequiredArgsConstructor;
+
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class RedisCache {
+	
+	private int expiryInSeconds = 60*30;
+	
+	private RedissonClient redisson ;
+	
+	private RMapCache<Object, Object> getCache(final String region) {
+        return redisson.getMapCache(region);
+    }
+	
+	@SuppressWarnings("unchecked")
+	public <T> T get(final String region, final Object key) {
+        T cacheItem = (T) getCache(region).get(key);
+        return cacheItem;
+    }
+	
+	@SuppressWarnings("unchecked")
+    public <T> T getAll(final String region) {
+        return (T) getCache(region).values();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getAllKeys(final String region) {
+        T cacheItem = (T) getCache(region).readAllKeySet();
+        return cacheItem;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getAllValues(final String region) {
+        T cacheItem = (T) getCache(region).readAllValues();
+        return cacheItem;
+    }
+
+    public void set(final String region, final Object key, Object value) {
+        set(region, key, value, expiryInSeconds);
+    }
+
+    public void set(final String region, final Object key, Object value, final long timeoutInSeconds) {
+        set(region, key, value, timeoutInSeconds, TimeUnit.SECONDS);
+    }
+
+    public void set(final String region, final Object key, Object value, final long timeout, final TimeUnit unit) {
+        RMapCache<Object, Object> cache = redisson.getMapCache(region);
+        if (timeout > 0L) {
+            cache.fastPut(key, value, timeout, unit);
+        } else {
+            cache.fastPut(key, value);
+        }
+    }
+    
+    public Object setIfAbsent(final String region, final Object key, Object value) {
+    	return setIfAbsent(region, key, value, expiryInSeconds);
+    }
+
+    public Object setIfAbsent(final String region, final Object key, Object value, final long timeoutInSeconds) {
+    	return setIfAbsent(region, key, value, timeoutInSeconds, TimeUnit.SECONDS);
+    }
+
+    public Object setIfAbsent(final String region, final Object key, Object value, final long timeout, final TimeUnit unit) {
+        RMapCache<Object, Object> cache = redisson.getMapCache(region);
+        if (timeout > 0L) {
+        	return cache.putIfAbsent(key, value, timeout, unit);
+        } else {
+            return cache.putIfAbsent(key, value);
+        }
+    }
+
+    public void del(final String region, final Object key) {
+        getCache(region).fastRemove(key);
+    }
+
+    public void mdel(final String region, final Collection<?> keys) {
+        getCache(region).fastRemove(keys.toArray(new Object[keys.size()]));
+    }
+
+    public void deleteRegion(final String region) {
+        getCache(region).clear();
+    }
+	
+
+}

+ 34 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/RedissonConfig.java

@@ -0,0 +1,34 @@
+package com.mrxu.framework.starter.redisson;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.redisson.config.SingleServerConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+	
+    @Value("${spring.redis.host}")
+    private String redisHost;
+
+    @Value("${spring.redis.port}")
+    private Integer redisPort;
+    
+    @Value("${spring.redis.password}")
+    private String redisPassword;
+	
+    @Bean
+	public RedissonClient redisson() {
+		Config config = new Config();
+        String host = "redis://"+redisHost + ":" + redisPort;
+        SingleServerConfig single = config.useSingleServer();
+        single.setAddress(host);
+        single.setPassword(redisPassword);
+		RedissonClient redisson = Redisson.create(config);
+		return redisson;
+	}
+
+}

+ 21 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/anno/EnableLock.java

@@ -0,0 +1,21 @@
+package com.mrxu.framework.starter.redisson.anno;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+
+import com.mrxu.framework.starter.redisson.bean.LockAutoConfiguration;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(LockAutoConfiguration.class)
+public @interface EnableLock {
+
+}

+ 41 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/anno/Lock.java

@@ -0,0 +1,41 @@
+package com.mrxu.framework.starter.redisson.anno;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.mrxu.framework.starter.redisson.bean.LockPolicy;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Lock {
+
+	/**
+	 * 锁的策略
+	 */
+    LockPolicy policy() default LockPolicy.Lock;
+
+    /**
+     * 锁持续时间 单位秒 默认1分钟
+     */
+    int leaseTime() default 60;
+    
+    /**
+     * 自旋锁超时时间 单位毫秒
+     */
+    long waitTime() default 300L;
+
+    /**
+     * redis锁的key前缀 如果为空,则默认为类名+方法名
+     */
+    String keyPrex() default "";
+    
+    /**
+     * 未获取资源锁提示
+     */
+    String failMsg() default "请勿重复操作";
+    
+}

+ 19 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/anno/LockKey.java

@@ -0,0 +1,19 @@
+package com.mrxu.framework.starter.redisson.anno;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface LockKey {
+	
+    /**
+     * 用在model参数前时, 需指定用作key的字段名。
+     */
+    String[] keyField() default {};
+    
+}

+ 116 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/aop/LockManager.java

@@ -0,0 +1,116 @@
+package com.mrxu.framework.starter.redisson.aop;
+
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+import com.mrxu.framework.boot.util.MrxuAssert;
+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.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.mrxu.framework.starter.redisson.anno.Lock;
+import com.mrxu.framework.starter.redisson.anno.LockKey;
+import com.mrxu.framework.starter.redisson.bean.LockPolicy;
+
+/**
+ * @version v1
+ * @summary 分布式锁管理
+ * @Lock(policy = LockPolicy.Lock)
+   public boolean service(@LockKey int id, @LockKey String name) {
+ */
+@Aspect
+@Component
+public class LockManager {
+
+    private static Logger logger = LoggerFactory.getLogger(LockManager.class);
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Around(value = "@annotation(lock)", argNames = "pjp, lock")
+    public Object around(ProceedingJoinPoint pjp,Lock lock) throws Throwable {
+        Class<? extends Object> clazz = pjp.getTarget().getClass();
+        String methodName = pjp.getSignature().getName();
+        //获取参数
+        Object[] args = pjp.getArgs();
+        MethodSignature ms = (MethodSignature) pjp.getSignature();
+        Method m = ms.getMethod();
+
+        //获取锁前缀,如果没配置 取方法名
+        String keyPrix = lock.keyPrex();
+        if ("".equals(keyPrix)) {
+            keyPrix = clazz.getName() + ":" + methodName + ":";
+        }
+        //分布式锁的key
+        StringBuilder lockKey = new StringBuilder("lock:" + keyPrix);
+        //获取加注解的方法参数的值
+        Annotation[][] parameterAnnotations = m.getParameterAnnotations();
+        for (int i = 0; i < parameterAnnotations.length; i++) {
+            Annotation[] annotations = parameterAnnotations[i];
+            for (Annotation annotation : annotations) {
+                if (annotation.annotationType() == LockKey.class) {
+                    LockKey anno = (LockKey) annotation;
+                    if (anno.keyField() != null && anno.keyField().length > 0) {
+                        lockKey.append(genModelKey(args[i], anno.keyField()));
+                    }
+                    else {
+                        lockKey.append("_");
+                        lockKey.append(args[i]);
+                    }
+                }
+            }
+        }
+        LockPolicy policy = lock.policy();
+        RLock fairLock = redissonClient.getFairLock(lockKey.toString());
+        boolean getLock = false;
+        if(policy.equals(LockPolicy.Lock)) {
+        	getLock = fairLock.tryLock();
+        }
+        else if(policy.equals(LockPolicy.SpinLock)) {
+        	getLock = fairLock.tryLock(lock.waitTime(),lock.leaseTime(),TimeUnit.SECONDS);
+        }
+        else {
+        	getLock = fairLock.tryLock(Long.MAX_VALUE,lock.leaseTime(),TimeUnit.SECONDS);
+        }
+        //获取不到锁直接终止流程
+        MrxuAssert.isTrue(getLock,lock.failMsg());
+        try {
+        	return pjp.proceed();
+        }
+		finally {
+			fairLock.unlock();
+		}
+    }
+
+    private String genModelKey(Object model, String[] fields) throws Exception {
+        StringBuilder sb = new StringBuilder();
+        for (String field : fields) {
+            sb.append("_");
+            try {
+                sb.append(model.getClass().getMethod(buildGetMethod(field)).invoke(model));
+            }
+            catch (Exception e) {
+                logger.error("redisLock error: keyField '{}' 不存在", field, e);
+                throw e;
+            }
+        }
+        return sb.toString();
+    }
+
+    private String buildGetMethod(String field) {
+        StringBuilder sb = new StringBuilder("get");
+        sb.append(Character.toUpperCase(field.charAt(0)));
+        sb.append(field.substring(1, field.length()));
+        return sb.toString();
+    }
+
+}

+ 11 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/bean/LockAutoConfiguration.java

@@ -0,0 +1,11 @@
+package com.mrxu.framework.starter.redisson.bean;
+
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+@ComponentScan({"com.mrxu.framework.starter.redisson"})
+@EnableAspectJAutoProxy
+public class LockAutoConfiguration {
+
+}

+ 18 - 0
framework-starter/mrxu-starter-redisson/src/main/java/com/mrxu/framework/starter/redisson/bean/LockPolicy.java

@@ -0,0 +1,18 @@
+package com.mrxu.framework.starter.redisson.bean;
+
+public enum LockPolicy {
+	
+    /**
+     * 默认锁 失败立即返回
+     */
+    Lock,
+    /**
+     * 自旋锁 超时时间timeout
+     */
+    SpinLock,
+    /**
+     * 阻塞锁 无超时自旋
+     */
+    BlockLock
+    
+}

+ 4 - 0
framework-starter/pom.xml

@@ -16,4 +16,8 @@
     <packaging>pom</packaging>
     <packaging>pom</packaging>
     <name>framework-starter</name>
     <name>framework-starter</name>
     <description>mrxu starter</description>
     <description>mrxu starter</description>
+
+    <modules>
+        <module>mrxu-starter-redisson</module>
+    </modules>
 </project>
 </project>