diff --git a/demodump/src/main/java/org/example/sublist/ArrayListTest.java b/demodump/src/main/java/org/example/sublist/ArrayListTest.java new file mode 100644 index 0000000..92074a2 --- /dev/null +++ b/demodump/src/main/java/org/example/sublist/ArrayListTest.java @@ -0,0 +1,31 @@ +package org.example.sublist; + + +import java.util.Arrays; +import java.util.List; + +/** + * 数组测试 + * + * @author xiaomage + * @date 2022/12/25 + */ +public class ArrayListTest { + + public static void main(String[] args) { + List statusList = Arrays.asList(1, 2); + System.out.println(statusList); + System.out.println(statusList.contains(1)); + System.out.println(statusList.contains(3)); + + + statusList.add(3); + System.out.println(statusList.contains(3)); + + + + + + } + +} diff --git a/demodump/target/classes/org/example/haoshi/StopWatchTest.class b/demodump/target/classes/org/example/haoshi/StopWatchTest.class index 632c2fa..a18f35e 100644 Binary files a/demodump/target/classes/org/example/haoshi/StopWatchTest.class and b/demodump/target/classes/org/example/haoshi/StopWatchTest.class differ diff --git a/demodump/target/classes/org/example/sublist/ArrayListTest.class b/demodump/target/classes/org/example/sublist/ArrayListTest.class new file mode 100644 index 0000000..3d92936 Binary files /dev/null and b/demodump/target/classes/org/example/sublist/ArrayListTest.class differ diff --git a/redislockdemo/.idea/.gitignore b/redislockdemo/.idea/.gitignore new file mode 100644 index 0000000..2f488a5 --- /dev/null +++ b/redislockdemo/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../:\redislockdemo\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/redislockdemo/.idea/compiler.xml b/redislockdemo/.idea/compiler.xml new file mode 100644 index 0000000..b004c58 --- /dev/null +++ b/redislockdemo/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/redislockdemo/.idea/encodings.xml b/redislockdemo/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/redislockdemo/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/redislockdemo/.idea/jarRepositories.xml b/redislockdemo/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/redislockdemo/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/redislockdemo/.idea/misc.xml b/redislockdemo/.idea/misc.xml new file mode 100644 index 0000000..4b661a5 --- /dev/null +++ b/redislockdemo/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/redislockdemo/pom.xml b/redislockdemo/pom.xml new file mode 100644 index 0000000..8a5bb1b --- /dev/null +++ b/redislockdemo/pom.xml @@ -0,0 +1,319 @@ + + + 4.0.0 + + com.xiaomage + redislockdemo + 1.0-SNAPSHOT + + + + + 1.0.0 + + UTF-8 + UTF-8 + + 1.8 + + + 3.1.1 + 1.6.0 + 2.0.0 + 1.3.2 + 1.1.22 + 1.19 + 2.3.2 + 2.9.2 + 1.8.9 + 1.2.5 + 1.2.73 + 5.2.5 + 5.5.0 + 2.5 + 1.3.3 + 3.17 + 1.7 + 0.7.3 + [7.2.0, 7.2.99] + 1.67 + 2.8.6 + 2.1.3.RELEASE + 4.0.24.Final + 2.9.0 + 4.0.0 + + + + + + + org.springframework + spring-context + 5.3.23 + + + + org.redisson + redisson-spring-boot-starter + 3.14.1 + + + + + org.springframework + spring-aop + 5.3.22 + + + + + com.alibaba + fastjson + 1.2.73 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + + org.springframework.data + spring-data-redis + 2.1.3.RELEASE + + + + + commons-io + commons-io + 2.5 + + + + + commons-fileupload + commons-fileupload + 1.3.3 + + + + + + + junit + junit + 4.13 + test + + + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + + + com.github.penggle + kaptcha + ${kaptcha.version} + + + + + org.apache.shiro + shiro-core + ${shiro.version} + + + + + org.apache.shiro + shiro-spring + ${shiro.version} + + + + + org.apache.shiro + shiro-ehcache + ${shiro.version} + + + + + com.github.theborakompanioni + thymeleaf-extras-shiro + ${thymeleaf.extras.shiro.version} + + + + + org.springframework + spring-web + + + + + org.apache.commons + commons-lang3 + + + + + + eu.bitwalker + UserAgentUtils + ${bitwalker.version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.boot.version} + + + + + + org.springframework.data + spring-data-redis + ${spring-data-redis.version} + + + + org.apache.commons + commons-pool2 + ${commons-pool2.version} + + + io.netty + netty-all + ${netty-all.version} + + + + + com.github.oshi + oshi-core + ${oshi.version} + + + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + io.swagger + swagger-annotations + + + io.swagger + swagger-models + + + + + + + io.springfox + springfox-swagger-ui + ${swagger.version} + + + + com.github.xiaoymin + swagger-bootstrap-ui + ${swagger-bootstrap-ui.version} + + + + + commons-io + commons-io + ${commons.io.version} + + + + + commons-fileupload + commons-fileupload + ${commons.fileupload.version} + + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.apache.velocity + velocity + ${velocity.version} + + + + + com.alibaba + fastjson + ${fastjson.version} + + + + + us.codecraft + webmagic-core + ${webmagic.version} + + + us.codecraft + webmagic-extension + ${webmagic.version} + + + + + + + + com.google.code.gson + gson + ${gson.version} + + + org.projectlombok + lombok + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.1.17.RELEASE + pom + import + + + + + + \ No newline at end of file diff --git a/redislockdemo/redislockdemo.iml b/redislockdemo/redislockdemo.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/redislockdemo/redislockdemo.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/redislockdemo/src/main/java/com/xiaomage/MainApplication.java b/redislockdemo/src/main/java/com/xiaomage/MainApplication.java new file mode 100644 index 0000000..d616aac --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/MainApplication.java @@ -0,0 +1,20 @@ +package com.xiaomage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 主应用程序 + * + * @author Admin + * @date 2022/12/25 + */ +@SpringBootApplication +public class MainApplication { + + public static void main(String[] args) { + SpringApplication.run(MainApplication.class, args); + } + + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/annotation/Lock.java b/redislockdemo/src/main/java/com/xiaomage/annotation/Lock.java new file mode 100644 index 0000000..024b405 --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/annotation/Lock.java @@ -0,0 +1,25 @@ +package com.xiaomage.annotation; + +/** + * @className: Lock + * @author: xiaomage + * @date: 2022/12/25 + **/ +public @interface Lock { + + /** + * lock key + */ + String value(); + + /** + * 锁超时时间,默认5000ms + */ + long expireTime() default 5000L; + + /** + * 锁等待时间,默认50ms + */ + long waitTime() default 50L; + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/aop/LockAnnotationParser.java b/redislockdemo/src/main/java/com/xiaomage/aop/LockAnnotationParser.java new file mode 100644 index 0000000..6217c3f --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/aop/LockAnnotationParser.java @@ -0,0 +1,100 @@ +package com.xiaomage.aop; + + +import com.xiaomage.annotation.Lock; +import com.xiaomage.service.LockManager; +import com.xiaomage.vo.LockResult; +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.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.lang.reflect.Method; + +/** + * 锁注释解析器 + * + * @author Admin + * @date 2022/12/25 + */ + +@Aspect +@Component +@Slf4j +public class LockAnnotationParser { + @Resource + private LockManager lockManager; + + /** + * 定义切点 + */ + @Pointcut(value = "@annotation(com.xiaomage.annotation.Lock)") + private void cutMethod() { + } + + /** + * 切点逻辑具体实现 + */ + @Around(value = "cutMethod() && @annotation(lock)") + public Object parser(ProceedingJoinPoint point, Lock lock) throws Throwable { + String value = lock.value(); + if (isEl(value)) { + value = getByEl(value, point); + } + LockResult lockResult = lockManager.lock(getRealLockKey(value), lock.expireTime(), lock.waitTime()); + try { + return point.proceed(); + } finally { + lockManager.unlock(lockResult.getRLock()); + } + } + + /** + * 解析 SpEL 表达式并返回其值 + */ + private String getByEl(String el, ProceedingJoinPoint point) { + Method method = ((MethodSignature) point.getSignature()).getMethod(); + String[] paramNames = getParameterNames(method); + Object[] arguments = point.getArgs(); + + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(el); + EvaluationContext context = new StandardEvaluationContext(); + for (int i = 0; i < arguments.length; i++) { + context.setVariable(paramNames[i], arguments[i]); + } + + return expression.getValue(context, String.class); + } + + /** + * 获取方法参数名列表 + */ + private String[] getParameterNames(Method method) { + LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); + return u.getParameterNames(method); + } + + private boolean isEl(String str) { + return str.contains("#"); + } + + /** + * 锁键值 + */ + private String getRealLockKey(String value) { + return String.format("lock:%s", value); + } + + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/configuration/RedissonConfiguration.java b/redislockdemo/src/main/java/com/xiaomage/configuration/RedissonConfiguration.java new file mode 100644 index 0000000..8d7745a --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/configuration/RedissonConfiguration.java @@ -0,0 +1,39 @@ +package com.xiaomage.configuration; + + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; + +/** + * redisson配置 + * + * @author xiaomage + * @date 2022/12/25 + */ +public class RedissonConfiguration { + + // 此处更换自己的 Redis 地址即可 + @Value("${redis.addr}") + private String addr; + + @Bean + public RedissonClient redisson() { + Config config = new Config(); + config.useSingleServer() + .setAddress(String.format("%s%s", "redis://", addr)) + .setConnectionPoolSize(64) // 连接池大小 + .setConnectionMinimumIdleSize(8) // 保持最小连接数 + .setConnectTimeout(1500) // 建立连接超时时间 + .setTimeout(2000) // 执行命令的超时时间, 从命令发送成功时开始计时 + .setRetryAttempts(2) // 命令执行失败重试次数 + .setRetryInterval(1000); // 命令重试发送时间间隔 + + return Redisson.create(config); + } + + + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/entity/Student.java b/redislockdemo/src/main/java/com/xiaomage/entity/Student.java new file mode 100644 index 0000000..432cc1e --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/entity/Student.java @@ -0,0 +1,17 @@ +package com.xiaomage.entity; + + +import lombok.Data; + +/** + * 学生 + * + * @author Admin + * @date 2022/12/25 + */ +@Data +public class Student { + private String stuNo; + private String name; + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/enu/LockResultStatus.java b/redislockdemo/src/main/java/com/xiaomage/enu/LockResultStatus.java new file mode 100644 index 0000000..e09bdb6 --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/enu/LockResultStatus.java @@ -0,0 +1,22 @@ +package com.xiaomage.enu; + +/** + * @className: LockResultStatus + * @author: xiaomage + * @date: 2022/12/25 + **/ +public enum LockResultStatus { + + /** + * 通信正常,并且加锁成功 + */ + SUCCESS, + /** + * 通信正常,但获取锁失败 + */ + FAILURE, + /** + * 通信异常和内部异常,锁状态未知 + */ + EXCEPTION; +} diff --git a/redislockdemo/src/main/java/com/xiaomage/enu/ResponseEnum.java b/redislockdemo/src/main/java/com/xiaomage/enu/ResponseEnum.java new file mode 100644 index 0000000..1b249b1 --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/enu/ResponseEnum.java @@ -0,0 +1,10 @@ +package com.xiaomage.enu; + +/** + * @className: ResponseEnum + * @author: Kevin + * @date: 2022/12/25 + **/ +public enum ResponseEnum { + COMMON_FREQUENT_OPERATION_ERROR +} diff --git a/redislockdemo/src/main/java/com/xiaomage/exception/BizException.java b/redislockdemo/src/main/java/com/xiaomage/exception/BizException.java new file mode 100644 index 0000000..d63c23e --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/exception/BizException.java @@ -0,0 +1,6 @@ +package com.xiaomage.exception; + +public class BizException extends RuntimeException{ + public BizException(Object p0) { + } +} diff --git a/redislockdemo/src/main/java/com/xiaomage/service/LockManager.java b/redislockdemo/src/main/java/com/xiaomage/service/LockManager.java new file mode 100644 index 0000000..c3b2aea --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/service/LockManager.java @@ -0,0 +1,103 @@ +package com.xiaomage.service; + + +import com.xiaomage.enu.LockResultStatus; +import com.xiaomage.enu.ResponseEnum; +import com.xiaomage.exception.BizException; +import com.xiaomage.vo.LockResult; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +/** + * 锁管理器 + * + * @author xiaomage + * @date 2022/12/25 + */ +@Service +@Slf4j +public class LockManager { + + /** + * 最小锁等待时间 + */ + private static final int MIN_WAIT_TIME = 10; + + @Resource + private RedissonClient redisson; + + /** + * 加锁,加锁失败抛默认异常 - 操作频繁, 请稍后再试 + * + * @param key 加锁唯一key + * @param expireTime 锁超时时间 毫秒 + * @param waitTime 加锁最长等待时间 毫秒 + * @return LockResult 加锁结果 + */ + public LockResult lock(String key, long expireTime, long waitTime) { + return lock(key, expireTime, waitTime, () -> new BizException(ResponseEnum.COMMON_FREQUENT_OPERATION_ERROR)); + } + + /** + * 加锁,加锁失败抛异常 - 自定义异常 + * + * @param key 加锁唯一key + * @param expireTime 锁超时时间 毫秒 + * @param waitTime 加锁最长等待时间 毫秒 + * @param exceptionSupplier 加锁失败时抛该异常,传null时加锁失败不抛异常 + * @return LockResult 加锁结果 + */ + private LockResult lock(String key, long expireTime, long waitTime, Supplier exceptionSupplier) { + if (waitTime < MIN_WAIT_TIME) { + waitTime = MIN_WAIT_TIME; + } + + LockResult result = new LockResult(); + try { + RLock rLock = redisson.getLock(key); + try { + if (rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS)) { + result.setLockResultStatus(LockResultStatus.SUCCESS); + result.setRLock(rLock); + } else { + result.setLockResultStatus(LockResultStatus.FAILURE); + } + } catch (InterruptedException e) { + log.error("Redis 获取分布式锁失败, key: {}, e: {}", key, e.getMessage()); + result.setLockResultStatus(LockResultStatus.EXCEPTION); + rLock.unlock(); + } + } catch (Exception e) { + log.error("Redis 获取分布式锁失败, key: {}, e: {}", key, e.getMessage()); + result.setLockResultStatus(LockResultStatus.EXCEPTION); + } + + if (exceptionSupplier != null && LockResultStatus.FAILURE.equals(result.getLockResultStatus())) { + log.warn("Redis 加锁失败, key: {}", key); + throw exceptionSupplier.get(); + } + + log.info("Redis 加锁结果:{}, key: {}", result.getLockResultStatus(), key); + + return result; + } + + /** + * 解锁 + */ + public void unlock(RLock rLock) { + try { + rLock.unlock(); + } catch (Exception e) { + log.warn("Redis 解锁失败", e); + } + } + + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/service/TestService.java b/redislockdemo/src/main/java/com/xiaomage/service/TestService.java new file mode 100644 index 0000000..6545a99 --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/service/TestService.java @@ -0,0 +1,27 @@ +package com.xiaomage.service; + + +import com.xiaomage.annotation.Lock; +import com.xiaomage.entity.Student; +import com.xiaomage.vo.LockResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +@Slf4j +public class TestService { + + @Resource + private LockManager lockManager; + + + @Lock(value = "'test_'+#student.stuNo",expireTime = 3000, waitTime = 30) + public String test(Student student) { + // 业务代码 + return ""; + } + + +} diff --git a/redislockdemo/src/main/java/com/xiaomage/vo/LockResult.java b/redislockdemo/src/main/java/com/xiaomage/vo/LockResult.java new file mode 100644 index 0000000..25e0c08 --- /dev/null +++ b/redislockdemo/src/main/java/com/xiaomage/vo/LockResult.java @@ -0,0 +1,16 @@ +package com.xiaomage.vo; + + +import com.xiaomage.enu.LockResultStatus; +import lombok.Getter; +import lombok.Setter; +import org.redisson.api.RLock; + +@Setter +@Getter +public class LockResult { + + private LockResultStatus lockResultStatus; + + private RLock rLock; +} diff --git a/redislockdemo/src/main/resources/application.properties b/redislockdemo/src/main/resources/application.properties new file mode 100644 index 0000000..a00bfc9 --- /dev/null +++ b/redislockdemo/src/main/resources/application.properties @@ -0,0 +1,3 @@ +server.port= 8080 + +redis.addr = 192.168.56.10:6379 \ No newline at end of file