SpringCloud-01

SpringCloud-01,第1张

SpringCloud-01
    第二天:Euraka注册中心+Ribbon负载均衡+Feign简化REST
      SpringCloud介绍
        微服务架构演化

简而言之,微服务就是开发一组小型服务的方式来开发一个独立的应用系统,每个小型服务都运行在自己的进程中,并采用HTTP资源API轻量级的机制来互相通信。这些服务围绕业务功能进行构建,并能通过全自动的部署机制来进行独立部署。这些微服务可以使用不同的语言来编写,并且可以使用不同的数据库存储技术。

2.微服务的优点

    易于开发和维护

业务分拆,一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量较少。开发和维护单个微服务相对简单。每个微服务业务复杂度低,方便理解、维护和调试。整个应用由若干个微服务构成。

2.单个微服务启动快

单个微服务代码量少,启动比庞大的项目要快。

3.故障隔离

某个服务宕机,其他服务照常使用。单体项目就可能发生雪崩,造成整个系统宕机。

4.局部修改容易部署

传统单体项目修改一个功能就需要重新部署整个应用,而微服务只需对需要修改的服务重新部署,其他服务无需停止,甚至不相关的业务仍然可以继续执行。

5.技术栈不受限

在微服务中,支持技术异构,可以根据软件团队擅长的技术去实现,如java、c#、c、php等,也支持异构数据库mysql、oracle、sqlServer等。

3.定义

Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer's own laptop, bare metal data centres, and managed platforms such as Cloud Foundry.

Spring Cloud就是一个全家桶,整合了市面上最好最先进的技术,形成一个工具集,并简化其中的 *** 作,引领编程新方式。

4.官网

官网:     Redirecting…

手册:     http://cloud.spring.io/spring-cloud-static/Dalston.SR2/

中文:     Spring Cloud中文网-官方文档中文版

5.核心功能

configuration management        配置中心

service discovery               服务发现

circuit breakers                断路器

intelligent routing             智能路由

micro-proxy                     微代理

control bus                     控制总线

one-time tokens                 一次性令牌

global locks                    全局锁

leadership election             选举算法

distributed sessions            分布式会话

cluster state                   集群状态

6.核心组件架构图

7.规划内容和步骤

注册中心Eureka        eureka + provider-user + consumer-client

前端负载均衡Ribbon     consumer-ribbon

RESTFul简易封装       consumer-ribbon-feign

断路器支持            consumer-ribbon-feign-hystrix

API网关 Zuul          gateway-zuul

异构开发语言Sidecar    sidecar + nodejs

配置中心config        configserver+ consumer-ribbon-feign-hystrix

2.注册中心Eureka
    注册中心

注意它的特点,结构类似于MessageQueue消息队列,服务(提供者、消费者)先都注册到注册中心。它的特点在于,不会每次都去注册中心获取,而是有本地缓存,加快访问性能。内部含有心跳机制,当注册中心信息改变,自动快速获取新的信息到本地。心跳机制还保证分布式环境下,某个服务失败后,自动列表从注册中心移除。注册中心中保证所有可用的链接。

2.拓展:CAP定理

CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。它是分布式系统中最核心最重要的理论。

分布式系统的CAP理论:理论首先把分布式系统中的三个特性进行了如下归纳:

一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前 *** 作在C和A之间做出选择。

CAP理论就是说在分布式系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,要么选择CP要么选择AP,没有分布式系统能同时保证这三点。

3.ZooKeeper和Eureka对比

Eureka本身是Netflix开源的一款提供服务注册和发现的产品,并且提供了相应的Java封装。在它的实现中,节点之间相互平等,部分注册中心的节点挂掉也不会对集群造成影响,即使集群只剩一个节点存活,也可以正常提供发现服务。哪怕是所有的服务注册节点都挂了,Eureka Clients(客户端)上也会缓存服务调用的信息。这就保证了我们微服务之间的互相调用足够健壮。

Zookeeper主要为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。曾经是Hadoop项目中的一个子项目,用来控制集群中的数据,目前已升级为独立的顶级项目。很多场景下也用它作为Service发现服务解决方案。

对比

根据著名的CAP定理(C-数据一致性;A-服务可用性;P-服务对网络分区故障的容错性CAP这三个特性在任何分布式系统中不能同时满足,最多同时满足两个CP或者AP)。

ZooKeeper

Zookeeper是基于CP来设计的,即任何时刻对Zookeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性,但是它不能保证每次服务请求的可用性。从实际情况来分析,在使用Zookeeper获取服务列表时,如果zookeeper正在选主,或者Zookeeper集群中半数以上机器不可用,那么将无法获得数据。所以说,Zookeeper不能保证服务可用性。

诚然,在大多数分布式环境中,尤其是涉及到数据存储的场景,数据一致性应该是首先被保证的,这也是zookeeper设计成CP的原因。但是对于服务发现场景来说,情况就不太一样了:针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。因为对于服务消费者来说,能消费才是最重要的——拿到可能不正确的服务实例信息后尝试消费一下,也好过因为无法获取实例信息而不去消费。(尝试一下可以快速失败,之后可以更新配置并重试)所以,对于服务发现而言,可用性比数据一致性更加重要——AP胜过CP。

Eureka

而Spring Cloud Netflix在设计Eureka时遵守的就是AP原则。Eureka Server也可以运行多个实例来构建集群,解决单点问题,但不同于ZooKeeper的选举leader的过程,Eureka Server采用的是Peer to Peer对等通信。这是一种去中心化的架构,无master/slave区分,每一个Peer都是对等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的serviceUrl指向其他节点。每个节点都可被视为其他节点的副本。

如果某台Eureka Server宕机,Eureka Client的请求会自动切换到新的Eureka Server节点,当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的 *** 作都会进行replicateToPeer(节点间复制) *** 作,将请求复制到其他Eureka Server当前所知的所有节点中。

一个新的Eureka Server节点启动后,会首先尝试从邻近节点获取所有实例注册表信息,完成初始化。Eureka Server通过getEurekaServiceUrls()方法获取所有的节点,并且会通过心跳续约的方式定期更新。默认配置下,如果Eureka Server在一定时间内没有接收到某个服务实例的心跳,Eureka Server将会注销该实例(默认为90秒,通过eureka.instance.lease-expiration-duration-in-seconds配置)。当Eureka Server节点在短时间内丢失过多的心跳时(比如发生了网络分区故障),那么这个节点就会进入自我保护模式。

总结

ZooKeeper基于CP,不保证高可用,如果zookeeper正在选主,或者Zookeeper集群中半数以上机器不可用,那么将无法获得数据。Eureka基于AP,能保证高可用,即使所有机器都挂了,也能拿到本地缓存的数据。作为注册中心,其实配置是不经常变动的,只有发版(发布新的版本)和机器出故障时会变。对于不经常变动的配置来说,CP是不合适的,而AP在遇到问题时可以用牺牲一致性来保证可用性,既返回旧数据,缓存数据。

所以理论上Eureka是更适合作注册中心。而现实环境中大部分项目可能会使用ZooKeeper,那是因为集群不够大,并且基本不会遇到用做注册中心的机器一半以上都挂了的情况。所以实际上也没什么大问题。

4.拓展:分布式对关系型数据库的冲击

对于web网站来说,关系数据库的很多主要特性却往往无用武之地

数据库事务一致性需求

很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求并不高。允许实现最终一致性。

数据库的写实时性和读实时性需求

对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说发一条消息之后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。如:MQ消息队列机制,意义,可以解决瞬时的高并发,消峰填谷作用。

对复杂的SQL查询,特别是多表关联查询的需求

任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS类型的网站,从需求以及产品设计角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。

SNS:全称Social Networking Services,专指社交网络服务,包括了社交软件和社交网站。例如:脸谱facebook、腾讯QQ、微信等。

5.自我保护模式

什么是自我保护模式?默认配置下,如果Eureka Server每分钟收到心跳续约的数量低于一个阈值(instance的数量(60/每个instance的心跳间隔秒数)自我保护系数),并且持续15分钟,就会触发自我保护。在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学前面提到过,那就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。该模式可以通过eureka.server.enable-self-preservation = false来禁用,同时eureka.instance.lease-renewal-interval-in-seconds可以用来更改心跳间隔。

6.调用关系图

常见的服务发现产品:Eureka/Consul/ZooKeeper,Eureka轻量级。

3.Eureka服务端
    创建Maven工程

2.pom.xml

4.0.0
eureka.server
eureka-server
0.0.1-SNAPSHOT

org.springframework.boot
spring-boot-starter-parent
1.5.4.RELEASE



UTF-8
UTF-8
1.8



org.springframework.cloud
spring-cloud-starter-eureka-server





org.springframework.cloud
spring-cloud-dependencies
Dalston.SR1
pom
import



3.application.yml
security:
basic:
enabled: true
user:
name: user
password: password123
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://user:password123@localhost:8761/eureka
logging:
level:
root: INFO
4.EurekaServerApp.java
package cloud.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp.class, args);
}
}

5.监控地址

地址:http://localhost:8761

启动后形成一个控制台

4.服务提供者
    创建Maven工程

2.pom.xml

注意提供者是作为Eureka的客户端,这样启动后自动注册到EurekaServer中。


4.0.0
com.tedu
h1
0.0.1-SNAPSHOT

org.springframework.boot
spring-boot-starter-parent
1.5.4.RELEASE
 


UTF-8
UTF-8
1.8



org.springframework.cloud
spring-cloud-starter-eureka


org.springframework.boot
spring-boot-starter-web





org.springframework.cloud
spring-cloud-dependencies
Dalston.SR1
pom
import



3.application.yml

注意多个提供端的差异在于端口不同,将来同一个业务服务多实例如何标识呢?就是通过端口来标识。

server:
port: 7900
spring:
application:
name: provider-user
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
logging:
level:
root: INFO
4.HelloController.java
package cn.tedu.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return "1:"+name;
}
}
5.ProviderRunApp.java
package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ProviderRunApp {
public static void main(String[] args) {
SpringApplication.run(ProviderRunApp.class, args);
}
}

6.查看服务

5.服务提供者2
    创建Maven工程

创建项目,复制文件进行修改。主要

2.application.yml

修改端口为7901

server:
port: 7901
spring:
application:
name: provider-user
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
logging:
level:
root: INFO

3.HelloController.java

修改打印的页面展现的值,方便观察是哪个提供者响应的。

package cn.tedu.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return "2:"+name;
}
}

4.Provider2RunApp.java

修改类名

package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class Provider2RunApp {
public static void main(String[] args) {
SpringApplication.run(Provider2RunApp.class, args);
}
}

5.查看服务

6.消费者
    创建Maven工程

2.pom.xml

4.0.0
com.tedu
h1
0.0.1-SNAPSHOT

org.springframework.boot
spring-boot-starter-parent
1.5.4.RELEASE
 


UTF-8
UTF-8
1.8



org.springframework.cloud
spring-cloud-starter-eureka


org.springframework.boot
spring-boot-starter-web





org.springframework.cloud
spring-cloud-dependencies
Dalston.SR1
pom
import



3.application.yml
server:
port: 8010
spring:
application:
name: consumer-client
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
logging:
level:
root: INFO    

4.HelloController.java

RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name。

package cn.tedu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;

@GetMapping("/hello/{name}")
@ResponseBody
public String hello(@PathVariable String name){
String url = "http://localhost:7900/hello";   //直接访问
return this.restTemplate.getForObject(url, String.class);
}
}

5.ConsumerRunApp.java

重点在启动时要初始化RestTemplate对象,同时设置@LoadBalanced负载均衡

package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class ConsumerRunApp {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerRunApp.class, args);
}
}

6.测试

执行顺序:

先启动服务端    8761       eureka-server     EurekaServerApp
在启动提供者1   7900       provider-user     ProviderRunApp
在启动提供者2   7901       provider-user2       Provider2RunApp
最后启动消费者  8010       consumer-client   ConsumerRunApp

访问Eureka控制台:     http://localhost:8761/

访问请求:            http://localhost:8010/hello/tony

交替出现1:tony和2:tony,说明两个提供者交替执行。这里注意有时可能提供者2还未准备好不能工作,多刷一会就正常了。可以看出Ribbon默认的负载均衡策略是轮询。

7.负载均衡Ribbon
    问题

之前我们使用的是直接访问的方式,能否实现提供者端负载均衡呢?

public String hello(){
String url = "http://localhost:7900/hello";
return restTemplate.getForObject(url, String.class);
}

这是直接访问提供者,只能写死提供者的端口,并未使用Eureka注册中心,这样当服务宕机,我们也无从知道,只能访问超时。同时也无法“多例”服务进行支撑(负载均衡)。

2.Ribbon

Feign是netflix开发的声明式、模板化的http客户端,在使用时就像调用本地(服务消费者自己)的方法一般,帮助我们更加优雅的调用服务提供者的API。Feign自身支持springMVC,还整合了Eureka、Ribbon,极大的简化了Feign的使用。就整合Euraka而言,只需和普通的服务配置Eureka server的信息即可。整合Ribbon,就意味着不再需要通过标注@LoadBalanced的实例化后的RestTemplate去调用服务提供者方法了。Feign只需通过简单的定义一个接口即可实现负载均衡。

和nginx不同,它是客户端侧负载均衡。

3.负载均衡策略

常见提供的负载均衡算法有三种:

第一种也是默认为轮询

第二种为random随机

第三种为WeightedResponseTimeRule,响应时间

4.导包

无需引入jar包,在spring-cloud-start-euraka已经依赖了ribbon的jar包。

8.消费者Ribbon
    修改Maven工程内容

2.pom.xml

4.0.0
com.tedu
h1
0.0.1-SNAPSHOT

org.springframework.boot
spring-boot-starter-parent
1.5.4.RELEASE
 


UTF-8
UTF-8
1.8



org.springframework.cloud
spring-cloud-starter-eureka


org.springframework.boot
spring-boot-starter-web





org.springframework.cloud
spring-cloud-dependencies
Dalston.SR1
pom
import



注意:怎么没有依赖ribbon的jar包呢?

因为eureka中已经含有对ribbon的支持

3.application.yml
server:
port: 8010
spring:
application:
name: consumer-client
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
logging:
level:
root: INFO

4.HelloController.java

RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name。

package cn.tedu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;

@GetMapping("/hello/{name}")
@ResponseBody
public String hello(@PathVariable String name){
String url = "http://provider-user/hello/"+name;     //VIP虚拟IP,提供者的application-name:provider-user
return this.restTemplate.getForObject(url, String.class);
}
}

5.ConsumerRunApp.java

重点在启动时要初始化RestTemplate对象,同时设置@LoadBalanced负载均衡

package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class ConsumerRunApp {
@Bean
@LoadBalanced //Ribbon负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerRunApp.class, args);
}
}

6.测试

执行顺序:

先启动服务端    8761       eureka-server     EurekaServerApp
在启动提供者1   7900       provider-user     ProviderRunApp
在启动提供者2   7901       provider-user2       Provider2RunApp
最后启动消费者  8010       consumer-client   ConsumerRunApp

访问Eureka控制台:     http://localhost:8761/

访问请求:            http://localhost:8010/hello/tony

交替出现1:tony和2:tony,说明两个提供者交替执行。这里注意有时可能提供者2还未准备好不能工作,多刷一会就正常了。可以看出Ribbon默认的负载均衡策略是轮询。

7.小结:怎么把普通的消费者改为Ribbon消费者

Controller 

@RequestMapping("/hello")
public String hello(){
//provider-user就是Eureka中提供服务
String url = "http://provider-user/hello";
//发起对Eureka中某个服务进行访问,返回值类型和业务返回值类型一致
return restTemplate.getForObject(url, String.class);
}

启动类

@EnableEurekaClient
@SpringBootApplication
public class CustomerClientRunApp {
//初始化RestTemplate对象,Spring就初始化这个beand,就可以在Controller中注入
@Bean
@LoadBalanced //实现负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

9.SpringClound重构购物车
    创建Maven工程,提供者

1.创建Maven工程,消费端

2.CartController

新增方法和cart项目中的方法名、参数、返回值、请求链接一致

package com.tedu.controller;
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;
import org.springframework.web.client.RestTemplate;
import com.jt.common.vo.SysResult;
@RestController
public class CartController {
@Autowired //必须调用提供者
private RestTemplate restTemplate;

//我的购物车 /cart/query/{userId} RESTFul请求
@RequestMapping("/query/{userId}")
public SysResult myCart(@PathVariable Integer userId){
String url = "http://provider-jt-cart/cart/query/"+userId;
return restTemplate.getForObject(url, SysResult.class);
}   
}

10.拓展:Ribbon随机负载算法
    RibbonRuleConfig.java

自定义规则扩展对象

package cn.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;

@Configuration
public class RibbonRuleConfig {
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}

2.ConsumerRunApp.java

增加一个注解@RibbonClient即可

package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import cn.config.RibbonRuleConfig;
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="provider-user", configuration=RibbonRuleConfig.class)
public class ConsumerRunApp {
@Bean
@LoadBalanced //Ribbon负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerRunApp.class, args);
}
}

11.Feigh
    概念

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

Feigh是一个声明式web服务客户端。它能让开发web服务变得容易。使用Feign需要创建一个接口并注解它。它拥有包括Feign注解和JAX-RS注解的可插拔支持。它还支持可插拔的编码器和解码器。Spring Cloud拥有Spring MVC支持,并使用Spring Web中默认同样的HttpMessageConverters。在使用Feign时,Spring Cloud集成了Ribbon和Eureka来提供负载均衡的HTTP客户端。

总结:Feign简化HttpClient开发,封装了JAX-RS和springmvc的注解,学习成本很低。

12.消费者实现Feign
    创建Maven工程

2.pom.xml

 


4.0.0
cn.tedu
consumer-feign
0.0.1-SNAPSHOT

org.springframework.boot
spring-boot-starter-parent
1.5.4.RELEASE
 


UTF-8
UTF-8
1.8




org.springframework.cloud
spring-cloud-starter-hystrix



org.springframework.cloud
spring-cloud-starter-eureka



org.springframework.cloud
spring-cloud-starter-feign


org.springframework.boot
spring-boot-starter-web





org.springframework.cloud
spring-cloud-dependencies
Dalston.SR1
pom
import



3.application.yml
server:
port: 9001
spring:
application:
name: consumer-feign
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka

4.EurekaServiceFeign.java

以接口对外暴露,从而封装底层 *** 作。

package cn.tedu.client;
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;
// 这个接口相当于把原来的服务提供者项目当成一个Service类
@FeignClient(value="provider-user")
public interface EurekaServiceFeign {

@RequestMapping(value="/hello/{name}",method=RequestMethod.GET)
public String hello(@PathVariable("name") String name);
}
5.HelloController.java
package cn.tedu.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import cn.tedu.client.EurekaServiceFeign;
@RestController
public class HelloController {
@Autowired
private EurekaServiceFeign eurekaServiceFeign;

@GetMapping("/hello/{name}")
@ResponseBody
public String hello(@PathVariable String name){
return eurekaServiceFeign.hello(name);
}
}
6.FeignRunApp.java
package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringCloudApplication
@EnableFeignClients         //开启Feign
public class FeignRunApp {
public static void main(String[] args) {
SpringApplication.run(FeignRunApp.class, args);
}
}

7.常见的坑

只支持旧的@RequestMapping不支持新的@GetMapping()等

method=RequestMethod.GET 只支持POST方法,GET方法也会自动转到POST方法

@PathVariable("name") String name 必须写名称“name”,springmvc可以不写

启动超过1s会报超时,再刷新就可以正常访问,原因在于hystrix断路器的影响,稍差的机器就会发生。

8.测试

执行顺序:

先启动服务端    8761       eureka-server     EurekaServerApp
在启动提供者1   7900       provider-user     ProviderRunApp
最后启动消费者  9001       consumer-client   ConsumerRunApp

访问Eureka控制台:     http://localhost:8761/

访问请求:            http://localhost:9001/hello/hellen

出现1:hellen,页面出现,设置断点,发现提供者也进入了,Feign消费者也进入了。

13.拓展:Feign实现降级 CartFeignFallback 
直接实现消费者的CartFeign接口,给每个方法设置异常时的处理
package cn.jt.feign;
import org.springframework.stereotype.Component;
import cn.jt.common.vo.SysResult;
import cn.jt.pojo.Cart;
@Component //微服务访问异常则启用降级
public class CartFeignFallback implements CartFeign{
@Override
public SysResult mycart(Long userId) {
return SysResult.build(400, "mycart error.");
}
@Override
public SysResult save(Cart cart) {
return SysResult.build(400, "save error.");
}
@Override
public SysResult update(Cart cart) {
return SysResult.build(400, "update error.");
}
@Override
public SysResult delete(Cart cart) {
return SysResult.build(400, "delete error.");
}
}
2.修改接口CartFeign
@FeignClient(value="jt-cart-provider",fallback = CartFeignFallback.class)
public interface CartFeign {
3.application.yml
server:
port: 9001
spring:
application:
name: jt-cart
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
#feign集成hystrix必须开启
feign:
hystrix:
enabled: true

logging:
level:
root: INFO

14.Feign小结
    调用过程

首先,提供者provider-user和消费者custorm-feign都注册到Eureka中。用户请求feign中的controller,feign中的controller调用feign定义的接口方法。接口的方法根据注解去找到eureka注册中心中的provider-user地址,然后请求远程provider-user所在服务器的地址,然后调用远程的provider-user提供者的具体服务。提供者响应返回json,json被feign封装传输给“接口”的返回值,“接口”在返回给feign的controller,最终响应给用户。

2.自动创建实现类

Feign是典型的基于接口,基于动态代理技术自动生成代理对象。

设置断点,可以清晰的看到这个过程。先访问consumer-feign的controller;观察EurekaServiceFeign接口,如下图其实一个jdk动态代理类。

动态代理类根据配置的注解信息去Eureka中找到对应调用的提供者的链接信息,进行访问,断点就进入到provider-user的controller中具体执行,执行完成层层返回。


作者:Darren QQ :603026148 以上内容归Darren所有,如果有什么错误或者不足的地方请联系我,希望我们共同进步。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/zaji/5709806.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存