springBoot实现分布式锁(Spring integration+redis)
一、 redis安装
使用docker-compose安装所需的redis环境
version: '3'
services:
redis:
image: redis # redis镜像
container_name: my_redis
command: redis-server --requirepass 123456 #在命令中初始化 redis 的密码
ports:
- "6379:6379"
volumes:
- ./data:/data
phpredisadmin: # redis web可视化界面
environment:
- ADMIN_USER=admin #用户名
- ADMIN_PASS=admin #密码
- REDIS_1_HOST=redis #redis主机
- REDIS_1_PORT=6379 #redis端口
- REDIS_1_AUTH=123456 #redis密码
image: 172.26.206.220/library/phpredisadmin:1.0
depends_on:
- redis
links:
- redis
ports:
- "10001:80"
二、在项目的pom.xml加入依赖
1)Spring integration 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
2) spring integration redis 依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
3)spring data redis 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml添加配置
spring:
redis:
port: 6379
host: ***.***.***.***
password: 123456
RedisLockRegistry配置
package com.lzx.demo.configuration;
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;
/**
* 描述:锁配置
*
* @Auther: lzx
* @Date: 2019/6/17 15:06
*/
@Configuration
public class RedisLockConfiguration {
@Bean
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory){
return new RedisLockRegistry(redisConnectionFactory,"spring-cloud");
}
}
三、在代码中使用分布式锁
1)自定义锁注解LzxLockDistributed
package com.lzx.demo.annotation;
import java.lang.annotation.*;
/**
* 描述: 分布式锁注解
*
* @Auther: lzx
* @Date: 2019/6/17 16:24
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LzxLockDistributed {
String value() default "";
int time() default 30;
}
2)aop实现锁的获取和释放
package com.lzx.demo.aop;
import com.lzx.demo.annotation.LzxLockDistributed;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* 描述:添加了 LzxLockDistributed 注解 的Aop
*
* @Auther: lzx
* @Date: 2019/6/18 10:56
*/
@Component
@Aspect
@Slf4j
public class MethodLockAop {
private WebApplicationContext webApplicationContext;
public MethodLockAop(WebApplicationContext webApplicationContext) {
this.webApplicationContext = webApplicationContext;
}
@Pointcut("@annotation(com.lzx.demo.annotation.LzxLockDistributed)")
private void apiAop(){
}
@Around("apiAop()")
public Object aroundApi(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
LzxLockDistributed lzxLockDistributed = method.getAnnotation(LzxLockDistributed.class);
String localRegistry = lzxLockDistributed.value();
if(StringUtils.isBlank(localRegistry)){
throw new RuntimeException("获取 Registry beann 失败");
}
RedisLockRegistry redisLockRegistry = (RedisLockRegistry) webApplicationContext.getBean(lzxLockDistributed.value());
Lock lock = redisLockRegistry.obtain(signature.getName());
boolean b = false;
for(int i =0 ; i<3;i++){
b = lock.tryLock(lzxLockDistributed.time(), TimeUnit.SECONDS);
if(b){
break;
}else {
continue;
}
}
log.info("获取锁====="+b);
Object proceed = null;
try{
proceed = point.proceed();
}catch (Exception e){
throw e;
}finally {
try{
lock.unlock();
}catch (Exception e){
log.error(e.getMessage(),e);
}
}
return proceed;
}
}
3)使用注解实现对方法进行加锁
@LzxLockDistributed(value = "redisLockRegistry",time = 60)
public String redisLockTest() throws InterruptedException {
if(inventory >= 5){
return "已经抢购完了~~~";
}
String s = strArr[inventory];
Thread.sleep(10*1000);
inventory++;
return s;
}