Spring Cloud Netflix Eureka
传统的服务治理
通讯协议
XML-RPC -> XML 方法描述、方法参数 -> WSDL(WebServices 定义语言)
WebServices -> SOAP(HTTP、SMTP) -> 文本协议(头部分、体部分)
REST -> 通常是JSON/XML( Schema :类型、结构) -> 文本协议(HTTP Header、Body)
W3C Schema :xsd:string 原子类型,自定义自由组合原子类型
Java POJO : int、String
Response Header -> Content-Type: application/json;charset=UTF-8
Dubbo:Hession、 Java Serialization(二进制),跨语言不变,一般通过 Client(Java、C++)
二进制的性能是非常好(字节流,免去字符流(字符编码),免去了字符解释,机器友好、对人不友好)
序列化:把编程语言数据结构转换成字节流、反序列化:字节流转换成编程语言的数据结构(原生类型的组合)
Eureka服务端
第一步:先是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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lawt</groupId>
<artifactId>spring-cloud-eureka-server-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-eureka-server-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/>
</parent>
<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.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二步:启动类SpringCloudEurekaServerApplication
package com.lawt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class SpringCloudEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudEurekaServerApplication.class, args);
}
}
第三步:配置修改application.properties
### Eureka Server 应用名称
spring.application.name = spring-cloud-eureka-server
### Eureka Server 服务端口
server.port= 9090
### 取消服务器自我注册
eureka.client.register-with-eureka=false
### 注册中心的服务器,没有必要再去检索服务
eureka.client.fetch-registry = false
## Eureka Server 服务 URL,用于客户端注册
eureka.client.serviceUrl.defaultZone=\
http://localhost:${server.port}/eureka
启动 SpringCloudEurekaServerApplication
启动成功后访问http://localhost:9090/
到此,Eureka的服务端就启动完毕。
Eureka客户端
创建provider
父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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lawt</groupId>
<artifactId>spring-cloud-eureka-client-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 创建三个module-->
<modules>
<module>user-api</module>
<module>user-service-consumer</module>
<module>user-service-provider</module>
</modules>
<packaging>pom</packaging>
<name>spring-cloud-eureka-client-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
user-api的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-eureka-client-demo</artifactId>
<groupId>com.lawt</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-api</artifactId>
</project>
User实体类创建
package com.lawt.user.domain;
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
UserServic接口创建
package com.lawt.user.service;
import com.lawt.user.domain.User;
import java.util.Collection;
/**
* 用户服务
*/
public interface UserService {
/**
* 保存用户
*
* @param user
* @return 如果保存成功的话,返回<code>true</code>,
* 否则返回<code>false</code>
*/
boolean save(User user);
/**
* 查询所有的用户对象
*
* @return 不会返回<code>null</code>
*/
Collection<User> findAll();
}
user-service-provider的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-eureka-client-demo</artifactId>
<groupId>com.lawt</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service-provider</artifactId>
<dependencies>
<!-- 增加 用户 API 的依赖 -->
<dependency>
<groupId>com.gupao</groupId>
<artifactId>user-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
模拟持久层UserRepository
package com.lawt.user.repository;
import com.lawt.user.domain.User;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* {@link User 用户} 仓储
*/
@Repository
public class UserRepository {
private ConcurrentMap<Long, User> repository = new ConcurrentHashMap<>();
private static final AtomicLong idGenerator = new AtomicLong(0);
public Collection<User> findAll() {
return repository.values();
}
public boolean save(User user) {
Long id = idGenerator.incrementAndGet();
user.setId(id);
return repository.putIfAbsent(id, user) == null;
}
}
UserService接口具体实现类
package com.lawt.user.service;
import com.lawt.user.domain.User;
import com.lawt.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
/**
* {@link UserService 用户服务} 提供者实现
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public boolean save(User user) {
return userRepository.save(user);
}
@Override
public Collection<User> findAll() {
return userRepository.findAll();
}
}
修改application.properties
## Eureka 注册中心服务器端口
eureka.server.port = 9090
## 服务提供方端口
server.port = 7070
## Eureka Server 服务 URL,用于客户端注册
eureka.client.serviceUrl.defaultZone=\
http://localhost:${eureka.server.port}/eureka
## Management 安全失效
management.security.enabled = false
创建一个controller
package com.lawt.user.web.controller;
import com.lawt.user.domain.User;
import com.lawt.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
/**
* {@link UserService 用户服务} 提供方 REST API {@link RestController}
*/
@RestController
public class UserServiceProviderRestApiController {
@Autowired
private UserService userService;
/**
* @param user User
* @return 如果保存成功的话,返回{@link User},否则返回<code>null</code>
*/
@PostMapping("/user/save")
public User saveUser(@RequestBody User user) {
if (userService.save(user)) {
System.out.println("UserService 服务方:保存用户成功!" + user);
return user;
} else {
return null;
}
}
/**
* 罗列所有的用户数据
* @return 所有的用户数据
*/
@GetMapping("/user/list")
public Collection<User> list() {
return userService.findAll();
}
}
创建provider服务启动类
package com.lawt.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceProviderApplication.class, args);
}
}
启动UserServiceProviderApplication
类
再次刷新http://localhost:9090/
自此,provider注册成功。
创建consumer
创建consumer的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-eureka-client-demo</artifactId>
<groupId>com.lawt</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-consumer</artifactId>
<dependencies>
<!-- 增加 用户 API 的依赖 -->
<dependency>
<groupId>com.gupao</groupId>
<artifactId>user-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
修改application.properties
spring.application.name = user-service-consumer
## Eureka 注册中心服务器端口
eureka.server.port = 9090
## 服务消费方端口
server.port = 8080
## Eureka Server 服务 URL,用于客户端注册
eureka.client.serviceUrl.defaultZone=\
http://localhost:${eureka.server.port}/eureka
## Management 安全失效
management.security.enabled = false
创建代理类UserServiceProxy
package com.lawt.user.service;
import com.lawt.user.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
/**
* {@link UserService} Proxy 实现
*/
@Service
public class UserServiceProxy implements UserService {
private static final String PROVIDER_SERVER_URL_PREFIX = "http://user-service-provider";
/**
* 通过 REST API 代理到服务器提供者
*/
@Autowired
private RestTemplate restTemplate;
@Override
public boolean save(User user) {
User returnValue =
restTemplate.postForObject(PROVIDER_SERVER_URL_PREFIX + "/user/save", user, User.class);
return returnValue != null;
}
@Override
public Collection<User> findAll() {
return restTemplate.getForObject(PROVIDER_SERVER_URL_PREFIX + "/user/list", Collection.class);
}
}
创建UserRestApiController供app、pc、或者其他调用
package com.lawt.user.web.controller;
import com.lawt.user.domain.User;
import com.lawt.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
/**
* 用户服务 REST API
*/
@RestController
public class UserRestApiController {
@Autowired
private UserService userService;
/**
* @param name 请求参数名为“name”的数据
* @return 如果保存成功的话,返回{@link User},否则返回<code>null</code>
*/
@PostMapping("/user/save")
public User saveUser(@RequestParam String name) {
User user = new User();
user.setName(name);
if (userService.save(user)) {
return user;
} else {
return null;
}
}
/**
* 罗列所有的用户数据
* @return 所有的用户数据
*/
@GetMapping("/user/list")
public Collection<User> list() {
return userService.findAll();
}
}
启动类UserServiceConsumerApplication
package com.lawt.user;
import com.lawt.user.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* {@link UserService 用户服务} 消费引导类
*/
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceConsumerApplication.class, args);
}
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
启动,再次刷新http://localhost:9090/
以post访问http://localhost:8080/user/save
参数:name=zzzz
请求相应结果
到此为止,一个完整的Spring Cloud Netflix Eureka的demo已经完成。