Curator提供了zk场景的绝大部分实现,使用Curator就不必关心其内部算法,Curator提供了来实现分布式锁,用方法获取锁,以及用方法释放锁,同其他锁一样,方法需要放在finakky代码块中,确保锁能正确释放。
1.添加Maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
2.zookeeper.properties
zookeeper.server=182.92.234.232:2181
zookeeper.lockPath=/springboot/
3.ZookeeperConfig代码
@Configuration
@PropertySources(value = {@PropertySource("classpath:zookeeper.properties")})
public class ZookeeperConfig {
@Autowired
private Environment environment;
@Bean(initMethod = "init", destroyMethod = "destroy")
public ZookeeperClient zookeeperClient() {
String zookeeperServer = environment.getRequiredProperty("zookeeper.server");
String zookeeperLockPath = environment.getRequiredProperty("zookeeper.lockPath");
return new ZookeeperClient(zookeeperServer, zookeeperLockPath);
}
}
4.取锁客户端(ZookeeperClient)
public class ZookeeperClient {
private static final Logger logger = LoggerFactory.getLogger(ZookeeperClient.class);
private static final int SLEEP_TIME_MS = 1000;
private static final int MAX_RETRIES = 3;
@Setter @Getter
private String zookeeperServer;
@Setter @Getter
private String zookeeperLockPath;
public ZookeeperClient(String zookeeperServer, String zookeeperLockPath) {
this.zookeeperServer = zookeeperServer;
this.zookeeperLockPath = zookeeperLockPath;
}
@Getter
private CuratorFramework client;
public <T> T lock(AbstractZookeeperLock<T> mutex) {
String path = this.getZookeeperLockPath() + mutex.getLockPath();
InterProcessMutex lock = new InterProcessMutex(this.getClient(), path);
boolean success = false;
try {
try {
success = lock.acquire(mutex.getTimeout(), mutex.getTimeUnit());
} catch (Exception e) {
throw new RuntimeException("obtain lock error " + e.getMessage() + ", path " + path);
}
if (success) {
return (T) mutex.execute();
} else {
return null;
}
} finally {
try {
if (success){
lock.release();
}
} catch (Exception e) {
logger.error("release lock error {}, path {}", e.getMessage(), path);
}
}
}
public void init() {
this.client = CuratorFrameworkFactory.builder().connectString(this.getZookeeperServer()).retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME_MS, MAX_RETRIES)).build();
this.client.start();
}
public void destroy() {
try {
if (getClient() != null) {
getClient().close();
}
} catch (Exception e) {
logger.error("stop zookeeper client error {}", e.getMessage());
}
}
}
5.公用锁抽象类
public abstract class AbstractZookeeperLock<T> {
private static final int TIME_OUT = 5;
public abstract String getLockPath();
public abstract T execute();
public int getTimeout(){
return TIME_OUT;
}
public TimeUnit getTimeUnit(){
return TimeUnit.SECONDS;
}
}
6.新建测试锁类
public abstract class TestLock<String> extends AbstractZookeeperLock<String> {
private static final java.lang.String LOCK_PATH = "test_";
@Getter
private String lockId;
public TestLock(String lockId) {
this.lockId = lockId;
}
@Override
public java.lang.String getLockPath() {
return LOCK_PATH + this.lockId;
}
}
7.使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private ZookeeperClient zookeeperClient;
@Test
public void test1() {
String lockId = "123";
String result = zookeeperClient.lock(new TestLock<String>(lockId) {
@Override
public String execute() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.getLockId();
}
});
if (result == null) {
System.out.println("执行失败");
} else {
System.out.println("执行成功");
}
}
}