+ * 启动器 + *
+ * + * @author yangkai.shen + * @date Created in 2022-09-05 19:34 + */ +@SpringBootApplication +public class ZookeeperDistributedLockApplication { + + public static void main(String[] args) { + SpringApplication.run(ZookeeperDistributedLockApplication.class, args); + } + +} diff --git a/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZkClient.java b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZkClient.java new file mode 100644 index 0000000..61fe104 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZkClient.java @@ -0,0 +1,77 @@ +package com.xkcoding.distributed.lock.autoconfigure; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.zookeeper.*; + +import java.io.IOException; + +/** + *+ * zookeeper 操作类 + *
+ * + * @author yangkai.shen + * @date 2022-09-05 19:50 + */ +@Slf4j +public class ZkClient { + /** + * 连接地址 + */ + @Getter + private final String connectServer; + + /** + * 节点根路径,默认是 /locks + */ + @Getter + private final String lockRootPath; + + @Getter + private ZooKeeper zooKeeper; + + private static final String DEFAULT_ROOT_PATH = "/locks"; + + public ZkClient(String connectServer) { + this.connectServer = connectServer; + this.lockRootPath = DEFAULT_ROOT_PATH; + } + + public ZkClient(String connectServer, String lockRootPath) { + this.connectServer = connectServer; + this.lockRootPath = lockRootPath; + } + + public void init() { + try { + this.zooKeeper = new ZooKeeper(connectServer, 3000, new Watcher() { + @Override + public void process(WatchedEvent watchedEvent) { + if (Event.KeeperState.SyncConnected == watchedEvent.getState() && Event.EventType.None == watchedEvent.getType()) { + log.info("===========> zookeeper connected <==========="); + } + } + }); + // 判断根节点是否存在,不存在则创建 + if (this.zooKeeper.exists(lockRootPath, false) == null) { + this.zooKeeper.create(lockRootPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); + } + } catch (IOException | KeeperException | InterruptedException e) { + log.error("===========> zookeeper connect error <==========="); + throw new RuntimeException(e); + } + } + + public void destroy() { + if (this.zooKeeper != null) { + try { + zooKeeper.close(); + log.info("===========> zookeeper disconnected <==========="); + } catch (InterruptedException e) { + log.error("===========> zookeeper disconnect error <==========="); + throw new RuntimeException(e); + } + } + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLock.java b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLock.java new file mode 100644 index 0000000..0a395c8 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLock.java @@ -0,0 +1,156 @@ +package com.xkcoding.distributed.lock.autoconfigure; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.xkcoding.distributed.lock.api.DistributedLock; +import org.apache.zookeeper.*; +import org.apache.zookeeper.data.Stat; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + *+ * 基于 Zookeeper 实现的分布式锁 + *
+ * + * @author yangkai.shen + * @date 2022-09-05 19:35 + */ +public class ZookeeperDistributedLock extends DistributedLock { + + private final ZooKeeper zooKeeper; + + private final String lockRootPath; + + private final String lockNodePath; + + private final ThreadLocal+ * 基于 Zookeeper 分布式锁自动装配类 + *
+ * + * @author yangkai.shen + * @date 2022-09-05 19:36 + */ +@Configuration(proxyBeanMethods = false) +public class ZookeeperDistributedLockAutoConfiguration { + @Bean(initMethod = "init", destroyMethod = "destroy") + public ZkClient zkClient() { + return new ZkClient("127.0.0.1:2181"); + } + + @Bean + public ZookeeperDistributedLockClient distributedLockClient(ZkClient zkClient) { + return new ZookeeperDistributedLockClient(zkClient); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLockClient.java b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLockClient.java new file mode 100644 index 0000000..e1c29cb --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/java/com/xkcoding/distributed/lock/autoconfigure/ZookeeperDistributedLockClient.java @@ -0,0 +1,33 @@ +package com.xkcoding.distributed.lock.autoconfigure; + +import com.xkcoding.distributed.lock.api.DistributedLock; +import com.xkcoding.distributed.lock.api.DistributedLockClient; +import lombok.RequiredArgsConstructor; + +import java.util.concurrent.TimeUnit; + +/** + *+ * 获得一把 Zookeeper 分布式锁 + *
+ * + * @author yangkai.shen + * @date 2022-09-05 19:36 + */ +@RequiredArgsConstructor +public class ZookeeperDistributedLockClient implements DistributedLockClient { + private final ZkClient zkClient; + + /** + * 获取一把锁 + * + * @param lockKey 锁的标识 + * @param lockTime 锁的时间 + * @param timeUnit 锁的时间单位 + * @return 锁 + */ + @Override + public DistributedLock getLock(String lockKey, long lockTime, TimeUnit timeUnit) { + return new ZookeeperDistributedLock(zkClient, lockKey, lockTime, timeUnit); + } +} diff --git a/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/resources/application.yml b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/resources/application.yml new file mode 100644 index 0000000..113bd15 --- /dev/null +++ b/demo-distributed-lock/demo-distributed-lock-zookeeper/src/main/resources/application.yml @@ -0,0 +1,16 @@ +server: + port: 8080 + servlet: + context-path: /demo +spring: + sql: + init: + continue-on-error: true + mode: always + schema-locations: + - "classpath:db/schema.sql" + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/spring-boot-demo + username: root + password: root