@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface CacheLock { String prefix() default ""; // int expire() default 5; // TimeUnit timeUnit() default TimeUnit.SECONDS; String delimiter() default ":"; } 复制代码
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface CacheParam { String name() default ""; int order() default -1; } 复制代码
package com.xxx.xx.common.aop; import com.alibaba.excel.util.StringUtils; import com.xxx.xx.common.annotation.CacheBody; import com.xxx.xx.common.annotation.CacheLock; import com.xxx.xx.common.annotation.CacheParam; import com.xxx.xx.common.aop.dto.CacheParamDTO; import com.xxx.xx.common.dto.Ret; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.concurrent.locks.Lock; import org.apache.commons.lang3.ArrayUtils; 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.CodeSignature; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.redis.util.RedisLockRegistry; import org.springframework.stereotype.Component; /** * @Author: hlm * @Date: 2019/4/4 10:46 */ @Aspect @Component public class CacheLockAop { @Autowired private RedisLockRegistry redisLockRegistry; @Pointcut("@annotation(cacheLock)") public void cacheLockPointCut(CacheLock cacheLock) { } @Around("cacheLockPointCut(cacheLock)") public Object around(ProceedingJoinPoint joinPoint, CacheLock cacheLock) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); if (StringUtils.isEmpty(cacheLock.prefix())) { throw new RuntimeException("key不能为空, 请在@CacheLock中定义prefix=%s"); } CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature(); String[] parameterNames = codeSignature.getParameterNames(); //获取方法入参,组装key List<CacheParamDTO> cacheParamDTOList = new ArrayList<>(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (Annotation[] parameterAnnotation : parameterAnnotations) { int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation); for (Annotation annotation : parameterAnnotation) { if (annotation instanceof CacheParam) { CacheParamDTO cacheParamDTO = new CacheParamDTO(); if (StringUtils.isEmpty(((CacheParam) annotation).name())) { cacheParamDTO.setName(parameterNames[paramIndex]); } else { cacheParamDTO.setName(((CacheParam) annotation).name()); } cacheParamDTO.setOrder(((CacheParam) annotation).order()); cacheParamDTO.setValue(joinPoint.getArgs()[paramIndex].toString()); cacheParamDTOList.add(cacheParamDTO); } if (annotation instanceof CacheBody) { Object obj = joinPoint.getArgs()[paramIndex]; Class bodyClass = obj.getClass(); Field[] fields = bodyClass.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(CacheParam.class)) { Annotation fieldAnnotation = field.getAnnotation(CacheParam.class); field.setAccessible(true); CacheParamDTO cacheParamDTO = new CacheParamDTO(); if (StringUtils.isEmpty(((CacheParam) fieldAnnotation).name())) { cacheParamDTO.setName(field.getName()); } else { cacheParamDTO.setName(((CacheParam) fieldAnnotation).name()); } cacheParamDTO.setOrder(((CacheParam) fieldAnnotation).order()); cacheParamDTO.setValue((String) field.get(obj)); cacheParamDTOList.add(cacheParamDTO); } } } } } StringBuilder builder = new StringBuilder(); cacheParamDTOList.sort(Comparator.comparing(item -> item.getOrder())); for (CacheParamDTO cacheParamDTO : cacheParamDTOList) { builder.append(cacheLock.delimiter()) .append(cacheParamDTO.getName()) .append(cacheLock.delimiter()) .append(cacheParamDTO.getValue()); } final String key = cacheLock.prefix() + builder.toString(); //spring-integration对redis分布锁的支持,底层应该也是lua脚本的实现,可完美解决线程挂掉造成的死锁,以及执行时间过长锁释放掉,误删别人的锁 Lock lock = redisLockRegistry.obtain(key); Boolean lockFlag = lock.tryLock(); if (!lockFlag) { return new Ret<>("M4000", "系统繁忙,请重试"); } Object object = null; try { object = joinPoint.proceed(); } finally { lock.unlock(); } return object; } } 复制代码
package com.xxx.xx.common.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.integration.redis.util.RedisLockRegistry; /** * @Author: hlm * @Date: 2019/4/8 8:59 */ @Configuration public class RedisLockConfiguration { @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) { return new RedisLockRegistry(redisConnectionFactory, "locks"); } } 复制代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.0.4.RELEASE</version> </dependency> 复制代码
本人第一次发帖,望大佬给出意见,在下会十分感谢的