├── README.md ├── pom.xml └── src └── main ├── java ├── dubbo │ └── helloworld │ │ ├── ConsumerAction.java │ │ ├── DemoService.java │ │ ├── DemoServiceImpl.java │ │ └── StartProvider.java ├── kafka │ └── helloWorld │ │ ├── Consumer.java │ │ ├── KafkaProperties.java │ │ └── Produce.java └── zookeeper │ ├── CreateGroup │ ├── ConnectionWatcher.java │ ├── CreateGroup.java │ └── CreateGroupTest.java │ ├── DeleteGroup │ ├── DeleteGroup.java │ └── DeleteGroupTest.java │ ├── DistributedLock │ └── DistributedLock.java │ ├── DistributedQueue │ └── DistributedQueue.java │ └── HelloWorld.java └── resources └── helloDubbo ├── consumer.xml └── provider.xml /README.md: -------------------------------------------------------------------------------- 1 | # Java分布式应用学习笔记 2 | 代码目录结构 3 | ------ 4 | * zookeeper
5 | * dubbo
6 | * kafka
7 | 8 | 笔记详情 9 | ------ 10 | * [知乎专栏 - 编程之路](https://zhuanlan.zhihu.com/coding4fun)  
11 | * [分布式学习(1) ---- 初识Zookeeper](https://zhuanlan.zhihu.com/p/24996631)  
12 | * [分布式学习(2) ---- Zookeeper实现分布式锁](https://zhuanlan.zhihu.com/p/25010779)  
13 | * [分布式学习(3) ---- 初识Nginx](https://zhuanlan.zhihu.com/p/25102281)  
14 | * [分布式学习(4) ---- Spring Session + Redis实现分布式Session共享](https://zhuanlan.zhihu.com/p/25010950)  
15 | * [分布式学习(5) ---- 初识消息系统kafka](https://zhuanlan.zhihu.com/p/25212966)  
16 | * [分布式学习(6) ---- 深入kafka生产消费模型](https://zhuanlan.zhihu.com/p/25227580)  
17 | * [分布式学习(7) ---- 常见web攻防简易总结](https://zhuanlan.zhihu.com/p/25249464)  
18 | * [分布式学习(8) ---- 分布式网站优化简易总结](https://zhuanlan.zhihu.com/p/25324226)  
19 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | zookeeper-dubbo 8 | zookeeper-dubbo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 1.7 17 | 1.7 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.apache.zookeeper 28 | zookeeper 29 | 3.4.9 30 | 31 | 32 | com.101tec 33 | zkclient 34 | 0.10 35 | 36 | 37 | 38 | 39 | com.alibaba 40 | dubbo 41 | 2.4.9 42 | 43 | 44 | 45 | org.springframework 46 | spring-context 47 | 3.2.8.RELEASE 48 | runtime 49 | 50 | 51 | 52 | junit 53 | junit 54 | 4.11 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/dubbo/helloworld/ConsumerAction.java: -------------------------------------------------------------------------------- 1 | package dubbo.helloworld; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | /** 6 | * 消费者消费服务 7 | */ 8 | public class ConsumerAction { 9 | public static void main(String[] args) { 10 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/helloDubbo/consumer.xml"); 11 | DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理 12 | String hello = demoService.sayHello("KKys!"); // 执行远程方法 13 | System.out.println(hello); // 显示调用结果 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dubbo/helloworld/DemoService.java: -------------------------------------------------------------------------------- 1 | package dubbo.helloworld; 2 | 3 | /** 4 | * 定义服务接口: (该接口需单独打包,在服务提供方和消费方共享) 5 | */ 6 | public interface DemoService { 7 | String sayHello(String name); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/dubbo/helloworld/DemoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package dubbo.helloworld; 2 | 3 | /** 4 | * 在服务提供方实现接口:(对服务消费方隐藏实现) 5 | */ 6 | public class DemoServiceImpl implements DemoService { 7 | @Override 8 | public String sayHello(String name) { 9 | return "Hello dubbo : " + name; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/dubbo/helloworld/StartProvider.java: -------------------------------------------------------------------------------- 1 | package dubbo.helloworld; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * 启动服务提供方 9 | */ 10 | public class StartProvider { 11 | public static void main(String[] args) throws IOException { 12 | System.out.println("启动"); 13 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/helloDubbo/provider.xml"); 14 | context.start(); 15 | System.in.read(); // 按任意键退出 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/kafka/helloWorld/Consumer.java: -------------------------------------------------------------------------------- 1 | package kafka.helloWorld; 2 | 3 | import org.apache.kafka.clients.consumer.ConsumerRecord; 4 | import org.apache.kafka.clients.consumer.ConsumerRecords; 5 | import org.apache.kafka.clients.consumer.KafkaConsumer; 6 | import org.apache.kafka.common.TopicPartition; 7 | 8 | import java.util.*; 9 | 10 | 11 | /** 12 | * kafka消费者 13 | * Created by yaosheng on 2017/2/9. 14 | */ 15 | 16 | 17 | public class Consumer{ 18 | 19 | public static void main(String[] args) { 20 | Properties props = new Properties(); 21 | props.put("bootstrap.servers", "121.42.8.85:9092"); 22 | props.put("group.id", "test"); 23 | props.put("enable.auto.commit", "true"); 24 | props.put("auto.commit.interval.ms", "1000"); 25 | props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); 26 | props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); 27 | KafkaConsumer consumer = new KafkaConsumer<>(props); 28 | consumer.subscribe(Arrays.asList("test2")); 29 | while (true) { 30 | ConsumerRecords records = consumer.poll(100); 31 | for (ConsumerRecord record : records) 32 | System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/kafka/helloWorld/KafkaProperties.java: -------------------------------------------------------------------------------- 1 | package kafka.helloWorld; 2 | 3 | /** 4 | * Created by yaosheng on 2017/2/9. 5 | */ 6 | public interface KafkaProperties { 7 | final static String zkConnect = "121.42.8.85:2181,121.42.8.85:2182,121.42.8.85:2183"; 8 | final static String groupId = "group1"; 9 | final static String topic = "topic1"; 10 | final static String kafkaServer = "121.42.8.85:9092,121.42.8.85:9092,121.42.8.85:9092"; 11 | final static int kafkaProducerBufferSize = 64 * 1024; 12 | final static int connectionTimeOut = 20000; 13 | final static int reconnectInterval = 10000; 14 | final static String topic2 = "topic2"; 15 | final static String topic3 = "topic3"; 16 | final static String clientId = "SimpleConsumerDemoClient"; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/kafka/helloWorld/Produce.java: -------------------------------------------------------------------------------- 1 | package kafka.helloWorld; 2 | import org.apache.kafka.clients.producer.KafkaProducer; 3 | import org.apache.kafka.clients.producer.ProducerRecord; 4 | import org.apache.kafka.clients.producer.Producer; 5 | import java.util.Properties; 6 | 7 | 8 | 9 | /** 10 | * kafka生产者 11 | * Created by yaosheng on 2017/2/9. 12 | */ 13 | 14 | public class Produce { 15 | 16 | public static void main(String[] args) { 17 | System.out.println("begin produce"); 18 | connectionKafka(); 19 | System.out.println("finish produce"); 20 | } 21 | 22 | public static void connectionKafka() { 23 | Properties props = new Properties(); 24 | props.put("bootstrap.servers", "121.42.8.85:9092"); 25 | //ack是判别请求是否为完整的条件(就是是判断是不是成功发送了)。我们指定了“all”将会阻塞消息,这种设置性能最低,但是是最可靠的。 26 | //props.put("acks", "all"); 27 | //失败后重试次数 28 | props.put("retries", 0); 29 | //默认缓冲可立即发送,即遍缓冲空间还没有满,但是,如果你想减少请求的数量,可以设置linger.ms大于0,就把消息先加到缓存队列中,稍后一同发出 30 | //props.put("linger.ms", 1); 31 | //缓存未发送消息的大小 32 | props.put("batch.size", 16384); 33 | //控制生产者可用的缓存总量 34 | props.put("buffer.memory", 33554432); 35 | props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); 36 | props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); 37 | 38 | Producer producer = new KafkaProducer<>(props); 39 | for (int i = 0; i < 10; i++) { 40 | producer.send(new ProducerRecord("test2", Integer.toString(i), Integer.toString(i))); 41 | System.out.println("send成功"); 42 | try { 43 | //两秒发一次 44 | Thread.currentThread().sleep(2000); 45 | } catch (InterruptedException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | producer.close(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/CreateGroup/ConnectionWatcher.java: -------------------------------------------------------------------------------- 1 | package zookeeper.CreateGroup; 2 | 3 | import org.apache.zookeeper.WatchedEvent; 4 | import org.apache.zookeeper.Watcher; 5 | import org.apache.zookeeper.ZooKeeper; 6 | 7 | import java.io.IOException; 8 | import java.util.concurrent.CountDownLatch; 9 | 10 | /** 11 | * 连接的观察者,封装了zk的创建等 12 | * Created by yaosheng on 2017/1/17. 13 | * 14 | */ 15 | public class ConnectionWatcher implements Watcher { 16 | private static final int SESSION_TIMEOUT = 5000; 17 | 18 | protected ZooKeeper zk = null; 19 | private CountDownLatch countDownLatch = new CountDownLatch(1); 20 | 21 | public void process(WatchedEvent event) { 22 | Event.KeeperState state = event.getState(); 23 | 24 | if(state == Event.KeeperState.SyncConnected){ 25 | countDownLatch.countDown(); 26 | } 27 | } 28 | 29 | /** 30 | * 连接资源 31 | * @param hosts 32 | * @throws IOException 33 | * @throws InterruptedException 34 | */ 35 | public void connection(String hosts) throws IOException, InterruptedException { 36 | zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this); 37 | countDownLatch.await(); 38 | } 39 | 40 | /** 41 | * 释放资源 42 | * @throws InterruptedException 43 | */ 44 | public void close() throws InterruptedException { 45 | if (null != zk) { 46 | try { 47 | zk.close(); 48 | } catch (InterruptedException e) { 49 | throw e; 50 | }finally{ 51 | zk = null; 52 | System.gc(); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/java/zookeeper/CreateGroup/CreateGroup.java: -------------------------------------------------------------------------------- 1 | package zookeeper.CreateGroup; 2 | 3 | import org.apache.zookeeper.*; 4 | 5 | import java.io.IOException; 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | /** 9 | * Created by yaosheng on 2017/1/16. 10 | */ 11 | 12 | public class CreateGroup implements Watcher{ 13 | 14 | private static final int SESSION_TIMEOUT = 1000;//会话延时 15 | 16 | private ZooKeeper zk = null; 17 | 18 | private CountDownLatch countDownLatch = new CountDownLatch(1);//同步计数器 19 | 20 | 21 | /** 22 | * 这里我们使用了同步计数器CountDownLatch,在connect方法中创建执行了zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);之后, 23 | * 下边接着调用了CountDownLatch对象的await方法阻塞,因为这是zk客户端不一定已经完成了与服务端的连接,在客户端连接到服务端时会触发观察者调用process()方法, 24 | * 我们在方法里边判断一下触发事件的类型,完成连接后计数器减一,connect方法中解除阻塞。 25 | 还有两个地方需要注意:这里创建的znode的访问权限是open的,且该znode是持久化存储的。 26 | * 27 | */ 28 | @Override 29 | public void process(WatchedEvent event) { 30 | if(event.getState() == Event.KeeperState.SyncConnected){ 31 | countDownLatch.countDown();//计数器减一 32 | } 33 | } 34 | 35 | /** 36 | * 创建zk对象 37 | * 当客户端连接上zookeeper时会执行process(event)里的countDownLatch.countDown(),计数器的值变为0,则countDownLatch.await()方法返回。 38 | * @param hosts 39 | * @throws IOException 40 | * @throws InterruptedException 41 | */ 42 | public void connect(String hosts) throws IOException, InterruptedException { 43 | zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this); 44 | countDownLatch.await();//阻塞程序继续执行 45 | } 46 | 47 | /** 48 | * 创建group 49 | * 50 | * @param groupName 组名 51 | * @throws KeeperException 52 | * @throws InterruptedException 53 | */ 54 | public void create(String groupName) throws KeeperException, InterruptedException { 55 | String path = "/" + groupName; 56 | String createPath = zk.create(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE/*允许任何客户端对该znode进行读写*/, CreateMode.PERSISTENT/*持久化的znode*/); 57 | System.out.println("Created " + createPath); 58 | } 59 | 60 | /** 61 | * 关闭zk 62 | * @throws InterruptedException 63 | */ 64 | public void close() throws InterruptedException { 65 | if(zk != null){ 66 | try { 67 | zk.close(); 68 | } catch (InterruptedException e) { 69 | throw e; 70 | }finally{ 71 | zk = null; 72 | System.gc(); 73 | } 74 | } 75 | } 76 | 77 | public static void main(String[] args){ 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/CreateGroup/CreateGroupTest.java: -------------------------------------------------------------------------------- 1 | package zookeeper.CreateGroup; 2 | 3 | import org.apache.zookeeper.KeeperException; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by yaosheng on 2017/1/16. 12 | */ 13 | public class CreateGroupTest { 14 | private static String hosts = "xxx:2181"; 15 | private static String groupName = "zoo"; 16 | 17 | private CreateGroup createGroup = null; 18 | /** 19 | * init 20 | * @throws InterruptedException 21 | * @throws KeeperException 22 | * @throws IOException 23 | */ 24 | @Before 25 | public void init() throws KeeperException, InterruptedException, IOException { 26 | createGroup = new CreateGroup(); 27 | createGroup.connect(hosts); 28 | } 29 | 30 | @Test 31 | public void testCreateGroup() throws KeeperException, InterruptedException { 32 | createGroup.create(groupName); 33 | } 34 | 35 | /** 36 | * 销毁资源 37 | */ 38 | @After 39 | public void destroy() { 40 | try { 41 | createGroup.close(); 42 | createGroup = null; 43 | System.gc(); 44 | } catch (InterruptedException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/DeleteGroup/DeleteGroup.java: -------------------------------------------------------------------------------- 1 | package zookeeper.DeleteGroup; 2 | 3 | import org.apache.zookeeper.KeeperException; 4 | import zookeeper.CreateGroup.ConnectionWatcher; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Created by yaosheng on 2017/1/17. 10 | * zk.delete(path,version)方法的第二个参数是znode版本号,如果提供的版本号和znode版本号一致才会删除这个znode, 11 | * 这样可以检测出对znode的修改冲突。通过将版本号设置为-1,可以绕过这个版本检测机制,无论znode的版本号是什么,都会直接将其删除。 12 | */ 13 | public class DeleteGroup extends ConnectionWatcher { 14 | public void delete(String groupName) { 15 | String path = "/" + groupName; 16 | 17 | try { 18 | List children = zk.getChildren(path, false); 19 | 20 | for(String child : children){ 21 | zk.delete(path + "/" + child, -1); 22 | } 23 | zk.delete(path, -1);//版本号为-1, 24 | } catch (KeeperException e) { 25 | e.printStackTrace(); 26 | } catch (InterruptedException e) { 27 | e.printStackTrace(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/DeleteGroup/DeleteGroupTest.java: -------------------------------------------------------------------------------- 1 | package zookeeper.DeleteGroup; 2 | 3 | import org.apache.zookeeper.KeeperException; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by yaosheng on 2017/1/17. 12 | */ 13 | public class DeleteGroupTest { 14 | private static final String HOSTS = "xxx:2181"; 15 | private static final String groupName = "zoo"; 16 | 17 | private DeleteGroup deleteGroup = null; 18 | 19 | @Before 20 | public void init() throws IOException, InterruptedException { 21 | deleteGroup = new DeleteGroup(); 22 | deleteGroup.connection(HOSTS); 23 | } 24 | 25 | @Test 26 | public void testDelete() throws IOException, InterruptedException, KeeperException { 27 | deleteGroup.delete(groupName); 28 | } 29 | 30 | @After 31 | public void destroy() throws InterruptedException { 32 | if(null != deleteGroup){ 33 | try { 34 | deleteGroup.close(); 35 | } catch (InterruptedException e) { 36 | throw e; 37 | }finally{ 38 | deleteGroup = null; 39 | System.gc(); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/DistributedLock/DistributedLock.java: -------------------------------------------------------------------------------- 1 | package zookeeper.DistributedLock; 2 | 3 | import org.apache.zookeeper.*; 4 | import org.apache.zookeeper.data.Stat; 5 | 6 | import java.io.IOException; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.concurrent.CountDownLatch; 10 | 11 | /** 12 | * zookeeper实现分布式锁 13 | */ 14 | public class DistributedLock implements Watcher{ 15 | private int threadId; 16 | private ZooKeeper zk = null; 17 | private String selfPath; 18 | private String waitPath; 19 | private String PREFIX_OF_THREAD; 20 | private static final int SESSION_TIMEOUT = 10000; 21 | private static final String GROUP_PATH = "/lock"; 22 | private static final String SUB_PATH = "/lock/sub"; 23 | private static final String CONNECTION_STRING = "xxx:2181"; 24 | 25 | private static final int THREAD_NUM = 10; 26 | //确保连接zk成功; 27 | private CountDownLatch connectedSemaphore = new CountDownLatch(1); 28 | //确保所有线程运行结束; 29 | private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM); 30 | public DistributedLock(int id) { 31 | this.threadId = id; 32 | PREFIX_OF_THREAD = "【第"+threadId+"个线程】"; 33 | } 34 | public static void main(String[] args) { 35 | for(int i=0; i < THREAD_NUM; i++){ 36 | final int threadId = i+1; 37 | new Thread(){ 38 | @Override 39 | public void run() { 40 | try{ 41 | DistributedLock dc = new DistributedLock(threadId); 42 | dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT); 43 | //GROUP_PATH不存在的话,由一个线程创建即可; 44 | synchronized (threadSemaphore){ 45 | dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true); 46 | } 47 | dc.getLock(); 48 | } catch (Exception e){ 49 | System.out.println(("【第"+threadId+"个线程】 抛出的异常:")); 50 | e.printStackTrace(); 51 | } 52 | } 53 | }.start(); 54 | } 55 | try { 56 | threadSemaphore.await(); 57 | System.out.println("所有线程运行结束!"); 58 | } catch (InterruptedException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | /** 64 | * 获取锁 65 | * @return 66 | */ 67 | private void getLock() throws KeeperException, InterruptedException { 68 | selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); 69 | System.out.println(PREFIX_OF_THREAD+"创建锁路径:"+selfPath); 70 | if(checkMinPath()){ 71 | getLockSuccess(); 72 | } 73 | } 74 | 75 | /** 76 | * 创建锁节点 77 | * @param path 锁节点path 78 | * @param data 初始数据内容 79 | * @return 80 | */ 81 | public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException { 82 | if(zk.exists(path, needWatch)==null){ 83 | System.out.println(PREFIX_OF_THREAD + "节点创建成功, Path: " 84 | + this.zk.create( path, 85 | data.getBytes(), 86 | ZooDefs.Ids.OPEN_ACL_UNSAFE, 87 | CreateMode.PERSISTENT) 88 | + ", content: " + data ); 89 | } 90 | return true; 91 | } 92 | 93 | /** 94 | * 创建ZK连接 95 | * @param connectString ZK服务器地址列表 96 | * @param sessionTimeout Session超时时间 97 | */ 98 | public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException { 99 | zk = new ZooKeeper( connectString, sessionTimeout, this); 100 | connectedSemaphore.await(); 101 | } 102 | 103 | /** 104 | * 获取锁成功 105 | */ 106 | public void getLockSuccess() throws KeeperException, InterruptedException { 107 | if(zk.exists(this.selfPath,false) == null){ 108 | System.out.println(PREFIX_OF_THREAD+"本节点已不在了..."); 109 | return; 110 | } 111 | System.out.println(PREFIX_OF_THREAD + "获取锁成功,开始干活!"); 112 | Thread.sleep(2000); 113 | releaseConnection(); 114 | threadSemaphore.countDown(); 115 | } 116 | /** 117 | * 关闭ZK连接 118 | */ 119 | public void releaseConnection() { 120 | if ( this.zk !=null ) { 121 | try { 122 | this.zk.close(); 123 | } catch ( InterruptedException e ) {} 124 | } 125 | System.out.println(PREFIX_OF_THREAD + "工作完毕,释放锁"); 126 | } 127 | 128 | /** 129 | * 检查自己是不是最小的节点 130 | * @return 131 | */ 132 | public boolean checkMinPath() throws KeeperException, InterruptedException { 133 | List subNodes = zk.getChildren(GROUP_PATH, false); 134 | Collections.sort(subNodes); 135 | //判断此节点 136 | int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1)); 137 | switch (index){ 138 | case -1:{ 139 | System.out.println(PREFIX_OF_THREAD+"本节点已不在了..."+selfPath); 140 | return false; 141 | } 142 | case 0:{ 143 | System.out.println(PREFIX_OF_THREAD+"子节点中,我最小,可以获得锁了!哈哈"+selfPath); 144 | return true; 145 | } 146 | default:{ 147 | this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1); 148 | System.out.println(PREFIX_OF_THREAD+"排在我前面的节点是 "+waitPath); 149 | try{ 150 | zk.getData(waitPath, true, new Stat()); 151 | return false; 152 | }catch(KeeperException e){ 153 | if(zk.exists(waitPath,false) == null){ 154 | System.out.println(PREFIX_OF_THREAD+"排在我前面的"+waitPath+"已消失 "); 155 | return checkMinPath(); 156 | }else{ 157 | throw e; 158 | } 159 | } 160 | } 161 | } 162 | } 163 | @Override 164 | public void process(WatchedEvent event) { 165 | if(event == null){ 166 | return; 167 | } 168 | Event.KeeperState keeperState = event.getState(); 169 | Event.EventType eventType = event.getType(); 170 | //已经是连接到zookeeper的状态 171 | if ( Event.KeeperState.SyncConnected == keeperState) { 172 | if ( Event.EventType.None == eventType ) { 173 | System.out.println(PREFIX_OF_THREAD + "成功连接上ZK服务器" ); 174 | connectedSemaphore.countDown(); 175 | }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) { 176 | //监听节点被删除状态 177 | System.out.println(PREFIX_OF_THREAD + "watch说我前面那个节点挂了,我可以获取锁啦!!"); 178 | try { 179 | //判断当前节点是否为最小节点 180 | if(checkMinPath()){ 181 | getLockSuccess(); 182 | } 183 | } catch (KeeperException e) { 184 | e.printStackTrace(); 185 | } catch (InterruptedException e) { 186 | e.printStackTrace(); 187 | } 188 | } 189 | }else if ( Event.KeeperState.Disconnected == keeperState ) { 190 | //监听断开 191 | System.out.println(PREFIX_OF_THREAD + "与ZK服务器断开连接" ); 192 | } else if ( Event.KeeperState.AuthFailed == keeperState ) { 193 | //监听权限失败 194 | System.out.println(PREFIX_OF_THREAD + "权限检查失败" ); 195 | } else if ( Event.KeeperState.Expired == keeperState ) { 196 | //监听会话失效 197 | System.out.println(PREFIX_OF_THREAD + "会话失效" ); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/DistributedQueue/DistributedQueue.java: -------------------------------------------------------------------------------- 1 | package zookeeper.DistributedQueue; 2 | 3 | import org.apache.zookeeper.CreateMode; 4 | import org.apache.zookeeper.KeeperException; 5 | import org.apache.zookeeper.WatchedEvent; 6 | import org.apache.zookeeper.Watcher; 7 | import org.apache.zookeeper.ZooKeeper; 8 | import org.apache.zookeeper.ZooDefs.Ids; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * 链接:http://blog.fens.me/zookeeper-queue/ 14 | * 15 | * 基于ZooKeeper现实的一种同步的分步式队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。 16 | * 17 | * 设计思路 18 | 创建一个父目录 /queue,每个成员都监控(Watch)标志位目录/queue/start 是否存在,然后每个成员都加入这个队列, 19 | 加入队列的方式就是创建 /queue/x(i)的临时目录节点,然后每个成员获取 /queue 目录的所有目录节点,也就是 x(i)。 20 | 判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /queue/start 的出现,如果已经相等就创建 /queue/start。 21 | 22 | */ 23 | public class DistributedQueue { 24 | public static void main(String[] args) throws Exception { 25 | //模拟app1通过zk1提交x1,app2通过zk2提交x2,app3通过zk3提交x3 26 | doAction(1); 27 | doAction(2); 28 | doAction(3); 29 | } 30 | 31 | //以此在集群的3台机器上加入某成员 32 | public static void doAction(int client) throws Exception { 33 | String host1 = "xxx:2181"; 34 | String host2 = "xxx:2182"; 35 | String host3 = "xxx:2183"; 36 | ZooKeeper zk = null; 37 | switch (client) { 38 | case 1: 39 | zk = connection(host1); 40 | initQueue(zk); 41 | joinQueue(zk, 1); 42 | break; 43 | case 2: 44 | zk = connection(host2); 45 | initQueue(zk); 46 | joinQueue(zk, 2); 47 | break; 48 | case 3: 49 | zk = connection(host3); 50 | initQueue(zk); 51 | joinQueue(zk, 3); 52 | break; 53 | } 54 | } 55 | 56 | // 创建一个与服务器的连接 57 | public static ZooKeeper connection(String host) throws IOException { 58 | ZooKeeper zk = new ZooKeeper(host, 60000, new Watcher() { 59 | // 监控所有被触发的事件 60 | public void process(WatchedEvent event) { 61 | if (event.getType() == Event.EventType.NodeCreated && event.getPath().equals("/queue/start")) { 62 | System.out.println("Queue has Completed.Finish testing!!!"); 63 | } 64 | } 65 | }); 66 | return zk; 67 | } 68 | 69 | //初始化队列 70 | public static void initQueue(ZooKeeper zk) throws KeeperException, InterruptedException { 71 | 72 | System.out.println("WATCH => /queue/start"); 73 | 74 | //当这个znode节点被改变时,将会触发当前Watcher 75 | zk.exists("/queue/start", true); 76 | 77 | //如果/queue目录为空,创建此节点 78 | if (zk.exists("/queue", false) == null) { 79 | System.out.println("create /queue task-queue"); 80 | zk.create("/queue", "task-queue".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 81 | } else { 82 | System.out.println("/queue is exist!"); 83 | } 84 | } 85 | 86 | //成员加入队列 87 | public static void joinQueue(ZooKeeper zk, int x) throws KeeperException, InterruptedException { 88 | System.out.println("create /queue/x" + x + " x" + x); 89 | zk.create("/queue/x" + x, ("x" + x).getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); 90 | isCompleted(zk); 91 | } 92 | 93 | //判断队列是否已满 94 | public static void isCompleted(ZooKeeper zk) throws KeeperException, InterruptedException { 95 | //规定队列大小 96 | int size = 3; 97 | //查询成员数 98 | int length = zk.getChildren("/queue", true).size(); 99 | System.out.println("Queue Complete:" + length + "/" + size); 100 | if (length >= size) { 101 | System.out.println("create /queue/start start"); 102 | zk.create("/queue/start", "start".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/zookeeper/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package zookeeper; 2 | 3 | /** 4 | * Created by yaosheng on 2017/1/16. 5 | */ 6 | import java.io.IOException; 7 | import org.apache.zookeeper.*; 8 | import org.apache.zookeeper.data.Stat; 9 | 10 | public class HelloWorld { 11 | 12 | public static void main(String[] args) throws IOException, InterruptedException, KeeperException { 13 | //此语句执行完后执行process方法 14 | ZooKeeper zk = new ZooKeeper("xxx:2181", 300000, new DemoWatcher());//连接zk server 15 | 16 | String node = "/app1"; 17 | Stat stat = zk.exists(node, false);//检测/app1是否存在 18 | if (stat == null) { 19 | //创建节点 20 | String createResult = zk.create(node, "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 21 | System.out.println(createResult); 22 | } 23 | //获取节点的值 24 | byte[] b = zk.getData(node, false, stat); 25 | System.out.println(new String(b)); 26 | zk.close(); 27 | 28 | } 29 | 30 | static class DemoWatcher implements Watcher { 31 | @Override 32 | public void process(WatchedEvent event) { 33 | System.out.println("----------->"); 34 | System.out.println("path:" + event.getPath()); 35 | System.out.println("type:" + event.getType()); 36 | System.out.println("stat:" + event.getState()); 37 | System.out.println("<-----------"); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/resources/helloDubbo/consumer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/helloDubbo/provider.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------