Spring Cloud
简介
Spring Cloud 包含了许多子项目,提供了一些工具来快速构建分布式系统中一些常用模式,分布式配置管理、服务注册和发现、断路器、智能路由、全局锁等;
主要项目
- Spring Cloud Config
- Spring Cloud Netflix
- Spring Cloud Bus
-
Spring Cloud Zookeeper
…
Spring Cloud Netflix
简介
Spring Cloud Netflix通过自动配置集成到Spring Boot应用中,用几个简单的注解可以快速启用和配置您的应用程序来构建大型分布式系统。提供包括服务发现、断路器、智能路由和客户端负载均衡等。
特性
- Eureka实例可以注册和发现使用spring管理的bean
- 嵌入式Eureka服务器可以用声明式的Java配置创建
- Hystrix客户端可以用简单的注解驱动
- Java配置可以启用嵌入的Hystrix指示面板
-
客户端负载均衡
…
快速开始
Eureka服务器
Spring Cloud Netflix使用Eureka服务器来注册/发现服务
建立SpringBoot应用程序
pom.xml
<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>org.pretent.spring.cloud</groupId>
<artifactId>eurekaServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
application.properties
server.port =
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
至此Eureka服务器就搭建好了,只需要启动此SpringBoot应用即可。
在浏览器输入:http://localhost:8761/就可以看到eureka服务指示面板了
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TPBRWdWdEZspESjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DNwMzN1AjMwEjNwEDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
@EnableEurekaServer
只要在SpringBoot应用使用@EnableEurekaServe注解,就可以配置此应用为一个Eureka服务器了,用来提供服务注册/发现中心。
Eureka服务器高可用
为了避免Eureka服务器的单点故障,可以启用多个Eureka服务器来实现Eureka服务器集群,达到高可用的目的,任何一个Eureka服务器故障不会导致Eureka服务注册中心不可用
假设有两个Eureka服务端,分别为http://localhost:8761/eureka/ 和http://localhost:8762/eureka/
只需要修改8761和8762的Eureka服务分别指向另一个即可。
- 8761上的application.properties
server.port =
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
- 8762上的application.properties
server.port =
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
- Eureka客户端上的application.properties
Eureka 客户端
相对于Eureka服务端,向Eureka注册自己的服务和从Eureka获取服务发现服务统称为Eureka 客户端。
Eureka Client 服务提供者
pom.xml
<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>org.pretent.spring.cloud</groupId>
<artifactId>eurekaClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
</project>
Application.java
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableEurekaClient
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello world";
}
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
application.properties
server.port =
spring.application.name = user-service
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
至此Eureka客户端就配置好了,此SpringBoot应用既有Eureka客户端的功能。
eureka.client.serviceUrl.defaultZone:用来制定eureka服务器地址。
再次打开我们的eureka服务端http://localhost:8761/可以看到我们的user-service已经注册到eureka服务器了。
@EnableEurekaClient
@EnableEurekaClient:只要在SpringBoot应用使用@EnableEurekaClient注解,就可以配置此应用为一个Eureka客户端了,既可以想Eureka服务器注册自己的服务,也可以查询定位其他服务;
@EnableDiscoveryClient:使用@EnableEurekaClient只能连接到Enable Server。也可以试用@EnableDiscoveryClient。
Eureka Client 服务消费者
Feign是一个声明式的Web Service客户端,它使得访问web服务更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成。它具备可插拔的注解支持,Feign也支持可插拔的编码器和解码器。Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
pom.xml
<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>org.pretent.spring.cloud</groupId>
<artifactId>eureka-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
UsersService.java
import java.util.List;
import java.util.Map;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient("user-service")
public interface UsersService {
@RequestMapping(method = RequestMethod.GET, value = "/users")
List<Map> find();
@RequestMapping(method = RequestMethod.GET, value = "/users/{userId}")
Map get(@PathVariable("userId") String userId);
}
UsersController.java
import java.util.List;
import java.util.Map;
import org.pretent.spring.cloud.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UsersController implements UsersService {
@Autowired
private UsersService usersService;
@RequestMapping
public List<Map> find() {
System.out.println(usersService.getClass().getName());
return usersService.find();
}
@RequestMapping("{userId}")
public Map get(@PathVariable String userId) {
return usersService.get(userId);
}
}
Application.java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
application.properties
spring.application.name = user-consumer
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
启动此服务消费端,访问http://localhost:8080/users 就可以访问上面服务提供这提供的服务了,如果user-service启动了多个服务提供者,是被轮训调用的。
Hystrix 断路器
用来在服务调用失败后调用
Feign客户端已经支持Hystrix 断路器
UsersService.java
import java.util.List;
import java.util.Map;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(value = "user-service", fallback = UsersServiceFallback.class)
public interface UsersService {
@RequestMapping(method = RequestMethod.GET, value = "/users")
List<Map> find();
@RequestMapping(method = RequestMethod.GET, value = "/users/{userId}")
Map get(@PathVariable("userId") String userId);
}
改造加入UsersService
fallback = UsersServiceFallback.class
@FeignClient(value = “user-service”, fallback = UsersServiceFallback.class)
UsersServiceFallback.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Component;
@Component
public class UsersServiceFallback implements UsersService {
public List<Map> find() {
System.out.println("UsersService.find调用失败");
return new ArrayList();
}
public Map get(String userId) {
System.out.println("UsersService.get调用失败");
return new HashMap();
}
}
实现UsersService 接口并注册为Spring的bean
@Component