参考:https://www.jianshu.com/p/cb21c3b86126
MAC 安装 zookeeper
https://www.jianshu.com/p/5491d16e6abd
启动的时候,一直报错:
./zkServer.sh: line 173: -e /Users/xxx/Downloads/apache-zookeeper-3.5.6/data/zookeeper_server.pid: No such file or directory
经过仔细看 zkServer.sh 脚本,发现
114 ZOO_DATADIR="$(echo -e "${ZOO_DATADIR}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
这行里 echo -e 有问题,把 -e 去掉就 OK。
连接 ZK,写 ZK 时,碰到
KeeperException$UnimplementedException
通常这是zookeeper客户端和服务端版本不一致造成的,client版本高。
下载最新的zookeeper解决。
Producer 工程
建立 Spring boot 工程
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-zookeeper-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-zookeeper-producer</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>2.2.0.M2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: HelloWorld
cloud:
zookeeper:
connect-string: localhost:2181
discovery:
enabled: true
server:
port: 8081
endpoints:
restart:
enabled: true
logging:
level:
org.apache.zookeeper.ClientCnxn: WARN
Main 改造
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudZookeeperProducerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZookeeperProducerApplication.class, args);
}
}
HelloWorldController
@RestController
public class HelloWorldController {
@GetMapping("/helloworld")
public String HelloWorld() {
return "Hello World!";
}
}
Consumer 工程
pom.xml
与 Producer 工程的一致。
application.yml
spring:
application:
name: Greeting
cloud:
zookeeper:
connect-string: localhost:2181
server:
port: 8083
logging:
level:
org.apache.zookeeper.ClientCnxn: WARN
Main 改造
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudZookeeperConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZookeeperConsumerApplication.class, args);
}
}
HelloWorldClient
@Configuration
@EnableFeignClients
@EnableDiscoveryClient
public class HelloWorldClient {
@Autowired
private TheClient theClient;
@FeignClient(name = "HelloWorld")
interface TheClient {
@RequestMapping(path = "/helloworld", method = RequestMethod.GET)
@ResponseBody
String HelloWorld();
}
public String HelloWorld() {
return theClient.HelloWorld();
}
}
GreetingController
@RestController
public class GreetingController {
@Autowired
private HelloWorldClient helloWorldClient;
@GetMapping("/get-greeting")
public String greeting() {
return helloWorldClient.HelloWorld();
}
}
测试
启动 Producer Main
启动 Consumer Main
访问 Consumer
服务注册
- Producer ZK 节点
get /services/HelloWorld/495dc630-2b8e-4347-98d9-08c01847b3cb
{"name":"HelloWorld","id":"495dc630-2b8e-4347-98d9-08c01847b3cb","address":"10.0.0.6","port":8081,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"HelloWorld","metadata":{}},"registrationTimeUTC":1573325073906,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
- Customer ZK 节点
get /services/Greeting/c67ee628-2624-4792-adef-2298e47b9919
{"name":"Greeting","id":"c67ee628-2624-4792-adef-2298e47b9919","address":"10.0.0.6","port":8083,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"Greeting","metadata":{}},"registrationTimeUTC":1573326354388,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
1. 无论 Producer 还是 Consumer,在 ZK 上节点内容是一致的。实际上,Consumer 本身也可作为其他 Consumer 的 Producer。
2. 当服务停止而不可用,相应的 ZK 节点消失。
服务发现
HelloWorldClient
@Configuration
@EnableFeignClients
@EnableDiscoveryClient
public class HelloWorldClient {
@Autowired
private TheClient theClient;
@FeignClient(name = "HelloWorld")
interface TheClient {
@RequestMapping(path = "/helloworld", method = RequestMethod.GET)
@ResponseBody
String HelloWorld();
}
public String HelloWorld() {
return theClient.HelloWorld();
}
}
- Producer 在 ZK 上注册的 service 名字 HelloWorld 来自 application.yml 的配置:
spring:
application:
name: HelloWorld
- HelloWorldClient 中的 @FeignClient(name = "HelloWorld") 的 HelloWorld 即 Producer 的 app 名。
- 服务发现的关键在于 @EnableDiscoveryClient