/**
* <p>
* redis配置类
* </p>
*/
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
/**
* <p>
* redission配置类
* </p>
*/
@Configuration
@ConfigurationProperties(prefix = "redisson.singleserverconfig")
public class RedissonSpringDataConfig {
private static final Logger log = LoggerFactory.getLogger(RedissonSpringDataConfig.class);
private String address;
private int database;
private String password;
@Bean
public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
return new RedissonConnectionFactory(redisson);
}
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws JsonProcessingException {
log.debug("[RedissonSpringDataConfig][redisson]>>>> address: {}, database: {}, password: {}", address, database, password);
Config config = new Config();
SingleServerConfig sconfig= config.useSingleServer()
.setAddress(address)
.setDatabase(database);
// 如果redis设置了密码,这里不设置密码就会报“org.redisson.client.RedisAuthRequiredException: NOAUTH Authentication required”错误。
if(StringUtils.hasText(password)){
sconfig.setPassword(password);
}
return Redisson.create(config);
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getDatabase() {
return database;
}
public void setDatabase(int database) {
this.database = database;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
@TableName("tb_user")
@ApiModel(value = "User对象", description = "")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("年龄")
private String age;
@ApiModelProperty("性别,1-男,0-女。")
private String sex;
@ApiModelProperty("住址")
private String address;
@ApiModelProperty("创建时间")
private LocalDateTime createdAt;
@ApiModelProperty("创建人")
private String createdBy;
@ApiModelProperty("更新时间")
private LocalDateTime updatedAt;
@ApiModelProperty("更新人")
private String updatedBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public String getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name=" + name +
", age=" + age +
", sex=" + sex +
", address=" + address +
", createdAt=" + createdAt +
", createdBy=" + createdBy +
", updatedAt=" + updatedAt +
", updatedBy=" + updatedBy +
"}";
}
}
/**
* <p>
* 加锁解锁工具类
* </p>
*/
@Component
public class RedisLock {
private static final Logger log = LoggerFactory.getLogger(RedisLock.class);
// todo 待优化,最好使用自定义的线程池,自定义工作队列和最大线程数。
private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(4);
@Resource
private Redisson redisson;
/**
* Redission获取锁
*
* @param lockKey 锁名
* @param uuid 唯一标识
* @param delaySeconds 过期时间
* @param unit 单位
* @return 是否获取成功
*/
public boolean Rlock(String lockKey, final String uuid, long delaySeconds, final TimeUnit unit) {
RLock rLock = redisson.getLock(lockKey);
boolean success = false;
try {
// log.debug("===lock thread id is :{}", Thread.currentThread().getId());
success = rLock.tryLock(0, delaySeconds, unit);
} catch (InterruptedException e) {
log.error("[RedisLock][Rlock]>>>> 加锁异常: ", e);
}
return success;
}
/**
* Redission释放锁
*
* @param lockKey 锁名
*/
public void Runlock(String lockKey) {
RLock rLock = redisson.getLock(lockKey);
log.debug("[RedisLock][Rlock]>>>> {}, status: {} === unlock thread id is: {}", rLock.isHeldByCurrentThread(), rLock.isLocked(),
Thread.currentThread().getId());
rLock.unlock();
}
/**
* Redission延迟释放锁
*
* @param lockKey 锁名
* @param delayTime 延迟时间
* @param unit 单位
*/
public void delayUnlock(final String lockKey, long delayTime, TimeUnit unit) {
if (!StringUtils.hasText(lockKey)) {
return;
}
if (delayTime <= 0) {
Runlock(lockKey);
} else {
EXECUTOR_SERVICE.schedule(() -> Runlock(lockKey), delayTime, unit);
}
}
}
/**
* <p>
* 防重复提交注解的实现,使用AOP。
* </p>
*/
@Aspect
@Component
public class LockMethodAOP {
private static final Logger log = LoggerFactory.getLogger(LockMethodAOP.class);
@Resource
private RedisLock redisLock;
/**
* 这里注意,我的注解写在同一个包下,如果换目录,要改为@annotation(com.xxx.NotResubmit).
*/
@Around("execution(public * *(..)) && @annotation(NotResubmit)")
public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
// 获取到这个注解
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
NotResubmit lock = method.getAnnotation(NotResubmit.class);
final String lockKey = generateKey(pjp);
// 上锁
final boolean success = redisLock.Rlock(lockKey, null, lock.delaySeconds(), TimeUnit.SECONDS);
if (!success) {
// 这里也可以改为自己项目自定义的异常抛出
return ResponseEntity.badRequest().body(ResultEntity.fail(ResponseCodeEnum.FAIL.getCode(), "操作太频繁"));
}
return pjp.proceed();
}
private String generateKey(ProceedingJoinPoint pjp) {
StringBuilder sb = new StringBuilder();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
sb.append(pjp.getTarget().getClass().getName())//类名
.append(method.getName());//方法名
for (Object o : pjp.getArgs()) {
sb.append(o.toString());
}
return DigestUtils.md5DigestAsHex(sb.toString().getBytes(Charset.defaultCharset()));
}
}