增加 README.md 用例
This commit is contained in:
parent
97c9ab6ca3
commit
5cb814a58c
23
README.md
23
README.md
@ -66,18 +66,17 @@ spring-cloud:Finchley.SR2
|
||||
|
||||
## 3. spring-cloud samples
|
||||
|
||||
| samples | 描述 | 官方文档 |
|
||||
| ------------------------------------------------------------ | ----------------------------------- | ------------------------------------------------------------ |
|
||||
| spring-cloud | 微服务简介与用例说明 | |
|
||||
| [spring-cloud-Eureka](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka) | 服务的注册和发现 | [Service Discovery: Eureka Server](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-eureka-server.html) |
|
||||
| [spring-cloud-Eureka-cluster](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka-cluster) | eureka 高可用集群搭建 | [Service Discovery: Eureka Server](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-eureka-server.html) |
|
||||
| [spring-cloud-Ribbon](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-ribbon) | RestTemplate的使用、客户端负载均衡 | [Client Side Load Balancer: Ribbon](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-ribbon.html) |
|
||||
| [spring-cloud-OpenFeign](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-feign) | 声明式服务调用 | [Declarative REST Client: Feign](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-feign.html) |
|
||||
| [spring-cloud-Hystrix](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-hystrix) | 熔断器、熔断器监控、turbine聚合监控 | [Circuit Breaker: Hystrix Clients](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__circuit_breaker_hystrix_clients.html)<br/>[Hystrix metrics aggregation with Turbine](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-consul-turbine.html) |
|
||||
| [spring-cloud-zuul](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-zuul) | 网关服务 | [Router and Filter: Zuul](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__router_and_filter_zuul.html) |
|
||||
| [spring-cloud-sleuth-Zipkin](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-sleuth-zipkin) | 分布式系统服务追踪 | [Spring Cloud Sleuth](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__introduction.html#sleuth-adding-project) |
|
||||
| [spring-cloud-config-bus](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-config) | 配置中心 + 消息总线实现配置热更新 | [Spring Cloud Config Client](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__spring_cloud_config_client.html) |
|
||||
| [spring-cloud-stream](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-stream) | spring cloud 对消息服务的抽象整合 | [spring-cloud-stream](http://cloud.spring.io/spring-cloud-stream/single/spring-cloud-stream.html) |
|
||||
| samples | 描述 | 官方文档 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| [spring-cloud-Eureka](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka) | eureka 服务的注册和发现 | [Service Discovery: Eureka Server](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-eureka-server.html) |
|
||||
| [spring-cloud-Eureka-cluster](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka-cluster) | eureka 高可用集群搭建 | [Service Discovery: Eureka Server](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-eureka-server.html) |
|
||||
| [spring-cloud-Ribbon](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-ribbon) | ribbon客户端负载均衡 | [Client Side Load Balancer: Ribbon](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-ribbon.html) |
|
||||
| [spring-cloud-OpenFeign](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-feign) | openfeign 声明式服务调用 | [Declarative REST Client: Feign](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-feign.html) |
|
||||
| [spring-cloud-Hystrix](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-hystrix) | hystix 服务容错保护<br/>hystrix dashboard 断路器监控<br>turbine 断路器聚合监控 | [Circuit Breaker: Hystrix Clients](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__circuit_breaker_hystrix_clients.html)<br/>[Hystrix metrics aggregation with Turbine ](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi_spring-cloud-consul-turbine.html) |
|
||||
| [spring-cloud-zuul](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-zuul) | zuul 网关服务 | [Router and Filter: Zuul](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__router_and_filter_zuul.html) |
|
||||
| [spring-cloud-sleuth-Zipkin](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-sleuth-zipkin) | sleuth 分布式系统服务追踪 | [Spring Cloud Sleuth](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__introduction.html#sleuth-adding-project) |
|
||||
| [spring-cloud-config-bus](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-config) | config 分布式配置中心 <br>bus消息总线 实现配置热更新 | [Spring Cloud Config Client](https://cloud.spring.io/spring-cloud-static/Finchley.SR2/multi/multi__spring_cloud_config_client.html) |
|
||||
| [spring-cloud-stream](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-stream) | stream 对消息服务的抽象整合 | [spring-cloud-stream](http://cloud.spring.io/spring-cloud-stream/single/spring-cloud-stream.html) |
|
||||
|
||||
<br/>
|
||||
|
||||
|
378
spring-cloud/spring-cloud-feign/README.md
Normal file
378
spring-cloud/spring-cloud-feign/README.md
Normal file
@ -0,0 +1,378 @@
|
||||
# spring-cloud-feign
|
||||
|
||||
## 一、feign 简介
|
||||
|
||||
在上一个用例中,我们使用ribbon+restTemplate 实现服务之间的远程调用,实际上每一个调用都是模板化的内容,所以spring cloud Feign 在此基础上进行了进一步的封装。我们只需要定义一个接口并使用feign注解的方式来进行配置,同时采用springMvc 注解进行参数绑定就可以完成服务的调用。feign同时还内置实现了负载均衡、服务容错等功能。
|
||||
|
||||
|
||||
|
||||
## 二、项目结构
|
||||
|
||||
+ common: 公共的接口和实体类;
|
||||
+ consumer: 服务的消费者,采用feign调用产品服务;
|
||||
+ producer:服务的提供者;
|
||||
+ eureka: 注册中心。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/spring-cloud-feign.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 三、服务提供者的实现
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/feign-producer.png"/> </div>
|
||||
|
||||
#### 3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。
|
||||
|
||||
ProductService.java:
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 产品提供接口实现类
|
||||
*/
|
||||
@Service
|
||||
public class ProductService implements IProductService, ApplicationListener<WebServerInitializedEvent> {
|
||||
|
||||
private static List<Product> productList = new ArrayList<>();
|
||||
|
||||
public Product queryProductById(int id) {
|
||||
return productList.stream().filter(p->p.getId()==id).collect(Collectors.toList()).get(0);
|
||||
}
|
||||
|
||||
|
||||
public List<Product> queryAllProducts() {
|
||||
return productList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveProduct(Product product) {
|
||||
productList.add(product);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(WebServerInitializedEvent event) {
|
||||
int port = event.getWebServer().getPort();
|
||||
for (long i = 0; i < 20; i++) {
|
||||
productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
ProducerController.java:
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class ProducerController implements ProductFeign {
|
||||
|
||||
@Autowired
|
||||
private IProductService productService;
|
||||
|
||||
@GetMapping("products")
|
||||
public List<Product> productList() {
|
||||
return productService.queryAllProducts();
|
||||
}
|
||||
|
||||
@GetMapping("product/{id}")
|
||||
public Product productDetail(@PathVariable int id) {
|
||||
return productService.queryProductById(id);
|
||||
}
|
||||
|
||||
@PostMapping("product")
|
||||
public void save(@RequestBody Product product) {
|
||||
productService.saveProduct(product);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient
|
||||
|
||||
```java
|
||||
server:
|
||||
port: 8020
|
||||
# 指定服务命名
|
||||
spring:
|
||||
application:
|
||||
name: producer
|
||||
# 指定注册中心地址
|
||||
eureka:
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: http://localhost:8010/eureka/
|
||||
```
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
public class ProducerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ProducerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 四、服务消费者的实现
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/feign-consumer.png"/> </div>
|
||||
|
||||
#### 4.1 导入openfeign依赖
|
||||
|
||||
```xml
|
||||
<!-- feign 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### 4.2 指定注册中心地址,并在启动类上添加注解@EnableDiscoveryClient和@EnableFeignClients
|
||||
|
||||
@EnableFeignClients 会去扫描工程中所有用 @FeignClient 声明的 feign 客户端。
|
||||
|
||||
```java
|
||||
server:
|
||||
port: 8080
|
||||
# 指定服务命名
|
||||
spring:
|
||||
application:
|
||||
name: consumer
|
||||
# 指定注册中心地址
|
||||
eureka:
|
||||
client:
|
||||
serviceUrl:
|
||||
defaultZone: http://localhost:8010/eureka/
|
||||
```
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients
|
||||
public class ConsumerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ConsumerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3 创建服务调用公共接口
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 声明式服务调用
|
||||
*/
|
||||
public interface ProductFeign {
|
||||
|
||||
@GetMapping("products")
|
||||
List<Product> productList();
|
||||
|
||||
/**
|
||||
* 这是需要强调的是使用feign时候@PathVariable一定要用value指明参数,
|
||||
* 不然会抛出.IllegalStateException: PathVariable annotation was empty on param 异常
|
||||
*/
|
||||
@GetMapping("product/{id}")
|
||||
Product productDetail(@PathVariable(value = "id") int id);
|
||||
|
||||
|
||||
@PostMapping("product")
|
||||
void save(@RequestBody Product product);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
按照官方对于服务最佳化的推荐,这里我们的服务调用接口放在公共模块中,因为在实际的开发中,同一个服务调用接口可能被多个模块所使用。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/common-feign.png"/> </div>
|
||||
|
||||
|
||||
|
||||
#### 4.4 继承公共接口,创建CProductFeign, 用@FeignClient声明为feign客户端
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 声明式接口调用
|
||||
*/
|
||||
@FeignClient(value = "producer",configuration = FeignConfig.class)
|
||||
public interface CProductFeign extends ProductFeign {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.5 注入使用 feign 服务调用接口
|
||||
|
||||
```java
|
||||
@Controller
|
||||
@RequestMapping("sell")
|
||||
public class SellController {
|
||||
|
||||
@Autowired
|
||||
private CProductFeign cproductFeign;
|
||||
|
||||
@GetMapping("products")
|
||||
public String productList(Model model) {
|
||||
List<Product> products = cproductFeign.productList();
|
||||
model.addAttribute("products", products);
|
||||
return "products";
|
||||
}
|
||||
|
||||
@GetMapping("product/{id}")
|
||||
public String productDetail(@PathVariable int id, Model model) {
|
||||
Product product = cproductFeign.productDetail(id);
|
||||
model.addAttribute("product", product);
|
||||
return "product";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("product")
|
||||
public String save(@RequestParam String productName) {
|
||||
long id = Math.round(Math.random() * 100);
|
||||
Product product = new Product(id, productName, false, new Date(), 88);
|
||||
cproductFeign.save(product);
|
||||
return "redirect:products";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 五、启动测试
|
||||
|
||||
#### 5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务
|
||||
|
||||
feign 的依赖中导入了spring-cloud-starter-netflix-ribbon依赖,并且在内部实现了基于ribbon的客户端负载均衡,所以我们这里启动三个producer实例来观察负载均衡的情况。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/spring-cloud-ribbon-app.png"/> </div>
|
||||
|
||||
**服务注册中心:**
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/spring-cloud-ribbon-eureka.png"/> </div>
|
||||
|
||||
#### 5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/spring-cloud-ribbon-products-8020.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/spring-cloud-ribbon-products-8030.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/feign-8040.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 六、 feign 的服务容错
|
||||
|
||||
#### 6.1 feign 的依赖中默认导入了hystrix 的相关依赖,我们不需要额外导入,只需要开启相关配置即可
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/feign-hystrix-maven.png"/> </div>
|
||||
|
||||
|
||||
|
||||
#### 6.2 在application.yml 中开启hystrix
|
||||
|
||||
```yml
|
||||
feign:
|
||||
hystrix:
|
||||
# 如果为true,则OpenFign客户端将使用Hystrix断路器进行封装 默认为false
|
||||
enabled: true
|
||||
```
|
||||
|
||||
#### 6.3 创建`CProductFeignImpl`,继承feign接口(CProductFeign),定义熔断时候的回退处理
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 定义发生熔断时候的回退处理。除了继承自CProductFeign,还需要用@Component声明为spring的组件
|
||||
*/
|
||||
@Component
|
||||
public class CProductFeignImpl implements CProductFeign {
|
||||
|
||||
// 发生熔断时候,返回空集合,前端页面会做容错显示
|
||||
@Override
|
||||
public List<Product> productList() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Product productDetail(int id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Product product) {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
页面的简单容错处理:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>产品列表</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3>产品列表:点击查看详情</h3>
|
||||
<form action="/sell/product" method="post">
|
||||
<input type="text" name="productName">
|
||||
<input type="submit" value="新增产品">
|
||||
</form>
|
||||
<ul>
|
||||
<#if (products?size>0) >
|
||||
<#list products as product>
|
||||
<li>
|
||||
<a href="/sell/product/${product.id}">${product.name}</a>
|
||||
</li>
|
||||
</#list>
|
||||
<#else>
|
||||
<h4 style="color: red">当前排队人数过多,请之后再购买!</h4>
|
||||
</#if>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 6.4 在 @FeignClient 注解中,用fallback参数指定熔断时候的回退处理
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 声明式接口调用
|
||||
*/
|
||||
@FeignClient(value = "producer",configuration = FeignConfig.class,fallback = CProductFeignImpl.class)
|
||||
public interface CProductFeign extends ProductFeign {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 6.5 测试熔断处理
|
||||
|
||||
hystrix 默认调用超时时间为2s ,这里我们使用线程休眠的方式来模拟超时熔断。
|
||||
|
||||
```java
|
||||
public List<Product> queryAllProducts() {
|
||||
/*用于测试 hystrix 超时熔断
|
||||
try {
|
||||
int i = new Random().nextInt(2500);
|
||||
Thread.sleep(i);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
return productList;
|
||||
}
|
||||
```
|
||||
|
||||
测试结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/feign-hystrix.png"/> </div>
|
@ -7,7 +7,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 声明式接口调用
|
||||
* @description : 声明式服务调用
|
||||
*/
|
||||
public interface ProductFeign {
|
||||
|
||||
|
@ -9,11 +9,12 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 定义发生错误时候的熔断处理。除了继承自CProductFeign,还需要用@Component声明为spring的组件
|
||||
* @description : 定义发生熔断时候的回退处理。除了继承自CProductFeign,还需要用@Component声明为spring的组件
|
||||
*/
|
||||
@Component
|
||||
public class CProductFeignImpl implements CProductFeign {
|
||||
|
||||
// 发生熔断时候,返回空集合,前端页面会做容错显示
|
||||
@Override
|
||||
public List<Product> productList() {
|
||||
return new ArrayList<>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user