概述:

微服务其实就是将一个大的架构进行模块化的拆分,每个模块就是一个微服务,各个微服务组合成一个整体:

实现微服务管理的方式:

Dubbo:

SpringCloud:

dubbo和SpringCloud对比:

dubbo只是实现类微服务的治理,但是springCloud实现微服务架构下的诸多组件

dubbo使用的是RPC通讯协议,SpringCloud采用的是RESTful完成通讯,由于SpringCloud实现的组件比较的多,所以SpringCloud的效率低于dubbo

1 不使用微服务管理工具远程调用示例:

生产端:

@RestController
public class StudentController {
    @GetMapping("/find/{age}")
    public Student find(@PathVariable int age) {
        return new Student("张三", age);
    }
}

消费端:

@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("{age}")
    public Student find(@PathVariable int age) {
        System.out.println(age);
        //知道访问的接口,然后完成拼串
        String url="http://localhost:8080/find/"+age;
        return  restTemplate.getForObject(url, Student.class) ;
    }
}

RestTemplate引入:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

SpringBoot环境下,依赖引入web的即可

RestTemplate远程调用是Spring进行封装的,但是跨域问题,底层已经解决!关于Resttemplate的api查看源码即可!

2 SpringCloud注册中心Eureka(使用这些注册中心会动态得到服务的提供方url)

Eureka的架构图(看图秒懂,其实其他的注册中心大同小异):

微服务注册Nacos注册的IP却是内网IP 微服务注册中心的组件_java

微服务注册Nacos注册的IP却是内网IP 微服务注册中心的组件_主机名_02

 关于Eureka的相关介绍,.......无关紧要的,废话就算啦:

Eureka的配置分为4部分:

server : eureka 的服务端配置

client : eureka 的客户端配置

instance : eureka 的实例配置

dashboard : eureka 的web控制台配置

其实烦的就是这些配置...所以我才在做模板,方便日后使用粘贴修改

eureka:  server:
    enable-self-preservation: false #是否开启自我保护机制,默认true即使服务有问题,也会保存(防止网络抖动等),
    eviction-interval-timer-in-ms: 50000 #清理死服务时间间隔,默认是60000
  dashboard:
    enabled: true #是否启用service的web控制台
    path: / #设置web控制台的访问路径
  
eureka:  instance:
    hostname: localhost #主机名字
    prefer-ip-address: true #否将自己的ip注册Eureka上,默认是不注册ip,注册的是主机名
    ip-address: #设置当前实例的ip
    instance-id: #修改instance显示的id
    lease-renewal-interval-in-seconds: 20 #Eureka客户端向服务端发送心跳的时间间隔
    lease-expiration-duration-in-seconds: 100 #超过该时间没有收到心跳,剔除服务
  client:
    service-url:
      defaultZone: #Eureka的service地址
    register-with-eureka: true #是否将自己的路径注册到eurea上
    fetch-registry: true # 是否从eureka上抓取数据

使用Eureka做为注册中心(这块注册中心使用集群实现高可用):

创建父项目使用maven进行统一的依赖管理(可以分开,看习惯):

实例搭建:

parent中pom.xml

<!--spring boot 环境 --><parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.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>
    <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    <!--spring cloud 版本-->
    <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<!--引入Spring Cloud 依赖-->
<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>

eureka的service:

pom依赖:

<dependencies>    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- eureka-server -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

service1配置:

#直接访问该端口就是Eureka的web控制台server: port: 8762 eureka: instance: hostname: nanfeng # 主机名 client: service-url: # 将本机服务注册到其他集群节点,这块设置的是两个节点,所以需要将本机的服务注册到另外一个服务上, # 若是单节点,这块就可以不配置了 # 下面这块改成需要注册的主机名,注意并不是本地主机名,是目标主机名名,在开发阶段采用端口识别,但是在上线后采用ip识别(端口号可以修改) defaultZone: http://localhost:8761/eureka register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 单节点不需要的,集群需要,eureka provider client 需要 fetch-registry: true # 是否需要从eureka中抓取路径。eureka server单节点不需要,集群需要 ,eureka consumer client 需要 server: enable-self-preservation: true # 是否开启自我保护机制(开启后即使注册到客户端的服务出现问题,也不会被清除,在开发测试不开启,上线后开启) eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔 spring: application: name: server #这个名字必须相同,同一个节点

service2

server: port: 8761 eureka: instance: hostname: localhost # 主机名 client: service-url: # 将本机服务注册到其他集群节点,这块设置的是两个节点,所以需要将本机的服务注册到另外一个服务上, # 若是单节点,这块就可以不配置了 # 下面这块改成需要注册的主机名,注意并不是本地主机名,是目标主机名名,在开发阶段采用端口识别,但是在上线后采用ip识别(端口号可以修改) defaultZone: http://nanfeng:8762/eureka register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 单节点不需要的,集群需要,eureka provider client 需要 fetch-registry: true # 是否需要从eureka中抓取路径。eureka server单节点不需要,集群需要 ,eureka consumer client 需要 server: enable-self-preservation: true # 是否开启自我保护机制(开启后即使注册到客户端的服务出现问题,也不会被清除,在开发测试不开启,上线后开启) eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔 spring: application: name: server #节点名字保证相同

service启动类添加注解@EnableEurekaServer,标注是一个Eureka的service服务:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServiceApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServiceApp.class, args);
    }
}

 注意:在搭建集群的时候启动两个服务相互注册的时候会报错,当两个服务都启动了,这个错误就不存在了!

客户端生产者和消费者的依赖:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>

生产端:

配置文件:

# 本地主机的启动端口号server:
  port: 8002

# eureka客户端服务的标准配置
eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    # 设置web控制台显示的 实例id,就是在注册中心显示的示实例的信息
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port}
    lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包,服务续约
    # 如果9秒没有发心跳包,服务器呀,你把我干掉吧,一般上线的服务都会在服务端开启自我服务的保护,
    #即使自己的服务出现问题,也不会将自己的服务杀掉,(可能指网络抖动,等文体,随后服务会回恢复正常)
    lease-expiration-duration-in-seconds: 9
  client:
    service-url:
      # eureka服务端地址,将来客户端使用该地址和eureka进行通信
      defaultZone: http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
  application:
    name: provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

 controller:

@RestController
public class StudentController {
    @GetMapping("/find/{age}")
    public Student find(@PathVariable int age) {
        return new Student("张三", age);
    }
}

启动类添加注解@EnableEurekaClient(生产端和消费端的启动类相同,就是添加注解):

@SpringBootApplication
@EnableEurekaClient
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

消费端:

 消费端配置文件:

# 本地主机的启动端口server:
  port: 8001

# eruake客户端消费的配置
eureka:
  instance:
    hostname: nanfeng # 主机名
  client:
    service-url:
      # eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
      defaultZone:  http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
  application:
    # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
    # 若是不设置会在eureka的控制台上无法显示信息
    name: consumer

RestTemplate配置类(这块使用了ribbon的注解@LoadBalanced 简化开发,ribbon和Eureka是同一家产品,Eureka中集成有ribbon,关于ribbon使用:Ribbon实现客户端负载均衡_楠~枫的博客-CSDN博客):

@Configuration
public class RestTemplateConfig {
    /*
     * 注入远程调用
     * */
    @LoadBalanced //ribbon注解:添加这个注解以后可以通过服务名字掉进行地址的绑定
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

controller(代码含有注释,参考):

@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
    @Autowired
    private RestTemplate restTemplate;
    //使用注册中心后
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("{age}")
    public Student find(@PathVariable int age) {
        //知道访问的接口,然后完成拼串
        String url = "http://localhost:8080/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }

    @GetMapping("discover/{age}")
    public Student findDiscovery(@PathVariable int age) {
        //通过discovery获取服务对象
        List<ServiceInstance> instances = discoveryClient.getInstances("provider");
       //判断集合是否有数据
        if (instances == null || instances.size() == 0) {
            //集合没有数据
            return null;
        }

        ServiceInstance instance = instances.get(0);
        String host = instance.getHost();//获取ip
        int port = instance.getPort();//获取端口
        //知道访问的接口,然后完成拼串
        String url = "http://"+host+":"+port+"/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }
    
    /*
     *使用aribbon后的简化调用,使用ribbon上面find2就不能使用原来的方式访问了,要痛过服务提供方的名称访问
     * */
    @GetMapping("ribbon/{age}")
    public Student findDiscoveryRibbon(@PathVariable int age) {
        String url = "http://provider/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }
}

关于Eureka的基本使用完结!配置文件超级烦,参考修改,为了偷懒,,,,,,,,,,,,,啦啦啦啦啦啦

3 SpringCloud注册中心Consul

Consul是go语言写的,是个软件包: 

官网地址:https://www.consul.io

度盘:https://pan.baidu.com/s/1tRvNmrG7-olM7UXjNiPoeg 
提取码:0vm6

废话不多说,直接用:

下载下来直接解压即可:

启动(解压目录下):

.\consul.exe agent -dev      # 开发形式启动,dev开发模式启动,不会持久化数据

访问控制台:localhost:8500

实例(基本上代码层面没啥改变,就是配置文件的形式):

父项目pom同Eureka实例:

pom依赖生产端和消费端相同

<!--consul 客户端--><dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

消费端配置:

server:  port: 8001

spring:
  cloud:
    consul:
      # 将服务的信息注册到端口
      host: localhost # consul 服务端的 ip
      port: 8500 # consul 服务端的端口 默认8500.consul的默认启动端口号
      discovery:
        service-name: ${spring.application.name} # 当前应用注册到consul的名称
        prefer-ip-address: true # 注册ip

  application:
    name: consumer # 应用名称

 生产端配置文件:

# 常规服务启动的端口server:
  port: 8002
spring:
  cloud:
    consul:
      # 将自己的信息注册到指定的地址
      host: localhost # consul 服务端的 ip
      port: 8500 # consul 服务端的端口 默认8500
      discovery:
        service-name: ${spring.application.name} # 当前应用注册到consul的名称
        prefer-ip-address: true # 注册ip

  application:
    name: provider # 应用名称

其实这两个配置没为神马区别:

消费端启动类:

@SpringBootApplication
@EnableDiscoveryClient//开启dis...
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class, args);
    }
}

 消费端RestTemplate引入:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

消费端Controller:

@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
    @Autowired
    private RestTemplate restTemplate;
    //使用注册中心后
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("{age}")
    public Student find(@PathVariable int age) {
        //知道访问的接口,然后完成拼串
        String url = "http://localhost:8080/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }

    @GetMapping("discover/{age}")
    public Student findDiscovery(@PathVariable int age) {
        //通过discovery获取服务对象
        List<ServiceInstance> instances = discoveryClient.getInstances("provider");
       //判断集合是否有数据
        if (instances == null || instances.size() == 0) {
            //集合没有数据
            return null;
        }

        ServiceInstance instance = instances.get(0);
        String host = instance.getHost();//获取ip
        int port = instance.getPort();//获取端口
        //知道访问的接口,然后完成拼串
        String url = "http://"+host+":"+port+"/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }
    
}

其他的省略,主要是配置文件!!!关于Consul基础使用就这啦,主要是配置文件

4 SpringCloud注册中心nacos

nacos是阿里巴巴的产物,是一个软件包:下载地址:https://github.com/alibaba/nacos/releases

度盘链接:https://pan.baidu.com/s/1_ZvotToFjgn0sHhYr92mow 
提取码:3ik4

啦啦啦啦啦,```````````````````````````````~~~~~~~~~~~~~~~~~~,直接使用吧!

解压后:

bin目录下的staetup.cmd双击启动
默认端口:8848
控制台:localhost:8848/nacos/#/login
     控制台的账号:nacos
     密码:nacos

linux和window相同,只是启动文件变成sh

启动完事

 其实还是学配置文件,真的是很烦这些配置文件

实例:

父项目依赖同Eureka实例

依赖(生产消费相同):


<!--nacos--><dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>0.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>1.1.0</version>
</dependency>
<!--web的起步依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置文件生产消费两边相同(修改即可):

server: port: 8002 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址 8848默认端口号 application: name: provider # 服务名称 

代码和Consul相同,同样的代码粘贴,,,,,

关于Nacos就这样吧

5 dubbo实现微服务管理:

明天吧...............................  

6 SpringCloud声明式服务调用Feign 

概述:

Feign是一种http客户端(主要用于消费端),用来实现http远程调用的,可以实现远程端调用像在本地方法一样,和Eureka是一家产品,在feign基层封装了ribbon和restful风格请求

实现原理:

 接口加注解的形式

Feign的日志级别为Debug,只识别Debug级别的日志

Feign超时设置(Feign的超时机制是建立在ribbon的基础上的),其实就是设置ribbon的超时机制,设置服务响应和处理的时间限制!若是服务端节点出现问题会雪崩!

雪崩:

所谓雪崩就是服务全部瘫痪,根本原因是某个服务调用过程中,由于服务端出现问题,调用端不断的调用,线程积压,最终瘫痪形成的链式反应:图示:

微服务注册Nacos注册的IP却是内网IP 微服务注册中心的组件_java_03

案例示例(基于上面搭建的Eureka做改进的):

消费端:

消费端添加feign的pom依赖:

<!--声明式服务调用--><!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

消费端配制文件(超时配置,日志配置)

# 本地主机的启动端口server:
  port: 8001

# eruake客户端消费的配置
eureka:
  instance:
    hostname: nanfeng # 主机名
  client:
    service-url:
      # eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
      defaultZone:  http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
  application:
    # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
    # 若是不设置会在eureka的控制台上无法显示信息
    name: consumer

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.itheima: debug

# 设置Feign的超时时间,但是Feign的底层实际是Ribbon
# 设置Ribbon的超时时间,
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

消费端Feign的接口(代码写法在注释中)

/**
 * feign的接口其实就是将RestTemplat的bean加载进来,将原来的请求地址:String url = "http://provider/find/" + age;进行了封装
 */
/*
* @FeignClient完成服务主机地址和名字以及端口的封装,SpringCloud对feign进行了封装,SpringMVC支持识别feign注解
**/
@FeignClient(value = "provider",configuration = FeignLogConfig .class)
public interface MyFeign {
    /*
    * @GetMapping保持和服务提供方的路径同即可
    */
    @GetMapping("/find/{age}")
   Student find(@PathVariable int age);
}

MyResttemplateConfig其实就是一个引入RestTemplate的配置类(这个在这可以不要,但是在controller中之前的案例还在,所以这块保存,否则之前的案例报错看不到对比)

/**
 * 其实就是一个RestTemplate的配置类
 */
@Configuration
public class MyResttemplateConfig {
     /*
    ribbon的注解,其实在这块有没有都可以,会自动识别的
     */
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

FeignLogConfig 日志配置类:

@Configuration
public class FeignLogConfig {


    /*
        NONE,不记录
        BASIC,记录基本的请求行,响应状态码数据
        HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
        FULL;记录完成的请求 响应数据


     */

    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

 controller类

@RestController
@RequestMapping("/consumer")
public class ComtstumerController {
    @Autowired
    private RestTemplate restTemplate;
    //使用注册中心后
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 注入feign
     */
    @Autowired
    private MyFeign myFeign;

    @GetMapping("{age}")
    public Student find(@PathVariable int age) {
        //知道访问的接口,然后完成拼串
        String url = "http://localhost:8080/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }

    @GetMapping("discover/{age}")
    public Student findDiscovery(@PathVariable int age) {
        //通过discovery获取服务对象
        List<ServiceInstance> instances = discoveryClient.getInstances("provider");
       //判断集合是否有数据
        if (instances == null || instances.size() == 0) {
            //集合没有数据
            return null;
        }

        ServiceInstance instance = instances.get(0);
        String host = instance.getHost();//获取ip
        int port = instance.getPort();//获取端口
        //知道访问的接口,然后完成拼串
        String url = "http://"+host+":"+port+"/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }

    /*
     *使用aribbon后的简化调用,使用ribbon上面find2就不能使用原来的方式访问了,要痛过服务提供方的名称访问
     * */
    @GetMapping("ribbon/{age}")
    public Student findDiscoveryRibbon(@PathVariable int age) {
        String url = "http://provider/find/" + age;
        return restTemplate.getForObject(url, Student.class);
    }


    /**
     * 通过Feigen接口调用
     */
    @GetMapping("feign/{age}")
    public Student findFeign(@PathVariable int age) {
        return myFeign.find(age);
    }
}

启动类开启Feign支持:

/**
 * 新版本部分SpringCloud组件的注解默认已经开启
 */
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient//开启dis支持...
/**
 * 开启feign的支持
 */
@EnableFeignClients
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class, args);
    }
}

 生产端和注册中心基于上面Eureka原来案例不变化,关于Feign声明式服务调用就这样了!!!!!!~~~使用参考修改即可!

7 SpringCloud的容错处理Hystix

概述:Hystix ,Eureka,Feign,Robbon都是一家的,Hystix是开源的一个延迟和容错库,防止出现雪崩的.......反正就是很溜!

作用:

隔离:信号量隔离/线程池隔离

信号量隔离,其实就是某个节点发来请求统计次数,在某个时间端内达到多少次限制请求,过一段时间然后缓慢释放一部分请求,若是没有问在逐渐放行请求

线程池隔离:设置线程数量,有空闲线程放行新的请求(实际使用的也是这个)

服务降级:针对某个服务出现异常/超时

 下面案例编码实现

熔断:这个实现原理在隔离中已经说了,两个关系很密切,隔离的条件达到后就会熔断,其实就是阻止请求

限流:就是熔断后缓慢放行请求的过程,根据限号量.空闲线程量

隔离,熔断,限流,只是Hystix不同时期的状态而已,三个组成hystix的工作过程!服务降级是对异常或者熔断的一种处理!

概念说明白了,案例实现:

案例(基于Feign案例添加和改动):

生产端:需要做的就是引入hystix依赖,编写降级方法,设置降级参数,启动类开启Hystixz支持

生产段pom依赖(生产端不需要):

<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>

生产端配置文件(基于Feign的配置文件无需修改/没有提及的都是基于之前案例的代码或者文件):

生产端代码(配置hystix降级注解的参数,写降级方法):

@RestController
public class StudentController {

    /**
     * @HystrixCommand设置服务降级的一些参数,注解参数解析: fallbackMethod:字符串类型参数,参数是同类的降级方法的方法名
     * commandProperties:设置一些降级参数信息,数组
     */
    @HystrixCommand(fallbackMethod = "findDomate", commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            //监控时间 默认5000 毫秒
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
            //失败次数。默认5000毫秒内失败20次,开启熔断器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
            //失败率 默认50%,也会开启熔断器
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
    })
    @GetMapping("/find/{age}")
    public Student find(@PathVariable int age) throws InterruptedException {
        Thread.sleep(5000);
        return new Student("张三", age);
    }

    /**
     * 降级方法的写法:
     * 1 和原来的方法参数相同
     * 2 和原来方法的返回值相同
     */
    public Student findDomate(int age) {
        return new Student("生产端降级了", 0);
    }
}

启动类开启hystix支持:

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix//开启Hystix支持
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

消费端 

消费端pom依赖基于feign不变:

消费端配置文件:

# 本地主机的启动端口server:
  port: 8001

# eruake客户端消费的配置
eureka:
  instance:
    hostname: nanfeng # 主机名
  client:
    service-url:
      # eureka服务端地址,将来客户端使用该地址和eureka进行通信,这块需要将服务自己的信息注册到集群环境中(下面的主机名在使用时修改即可),
      defaultZone:  http://localhost:8761/eureka,http://nanfeng:8762/eureka
spring:
  application:
    # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径,
    # 若是不设置会在eureka的控制台上无法显示信息
    name: consumer

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.itheima: debug

# 设置Feign的超时时间,但是Feign的底层实际是Ribbon
# 设置Ribbon的超时时间,超时会降级
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

#注意:在生产端也可以设置降级,但是设置的生产端的超时设置大于消费端的超时,
#会执行生产端的超时,消费端满足降级会先执行消费端降级
#开启Hystix支持
feign:
  hystrix:
    enabled: true

 Feign接口(配置降级方法):

/**
 * feign的接口其实就是将RestTemplat的bean加载进来,将原来的请求地址:String url = "http://provider/find/" + age;进行了封装
 */
/*
* @FeignClient完成服务主机地址和名字以及端口的封装,设置降级的实现类!SpringCloud对feign进行了封装,SpringMVC支持识别feign注解
**/
@FeignClient(value = "provider",configuration = FeignLogConfig.class,fallback = Demote.class)
public interface MyFeign {
    /*
    * @GetMapping保持和服务提供方的路径同即可
    */
    @GetMapping("/find/{age}")
   Student find(@PathVariable int age);
}

Feign接口实现类中写降级方法:

/**
 * feign的降级实现:
 * 定义类实现feign接口
 * 将实现类加入到ioc中
 */
@Component//需要ioc识别这个bean
public class Demote implements MyFeign {
    @Override
    public Student find(int age) {
        return new Student("消费端降级",0);
    }
}

 启动类基于feign案例:

基本上代码实现就到这了,该有的解释代码中已经做了说明,参考修改即可!

关于熔断器的工作机制:在解释hystix隔离时已经说明白了,这块在说一下:

达到隔离条件,进行熔断,过一段时间进行部分放行(即限流),若是放行的请求依然有问题,继续熔断,若是没有问题,全部放行,依次循环!

熔断器监控:啦啦啦,是有这个东西,但是应该是运维人员搞的,和我应该没多大关系!

8 SpringCloud的网关配置Gateay(网关)

概述:Gateway其实就是为诸多分布式服务提供统一的 Api管理,解决前端访问各个服务时路径的不同和身份验证等诸多问题!

理解图:

微服务注册Nacos注册的IP却是内网IP 微服务注册中心的组件_微服务_04

Nginx+ Lua.这个我目前还不是很熟悉,回头学习一下,再做整理!

理论都简单,烦人的还是配置文件:

主要使用:

静态路由:配置文件中写死

动态路由:将自己注册到注册中心,然后从注册中心获取uri

服务名称配置: 访问路径必须携带服务的名称:大写名称/小写名称

过滤器:主要是在请求的前后做一些操作   

过滤器方式: 

      pre :前置操作:在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换

      post 后置操作:在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等

GatewayFilter: 针对单个路由

GlobalFilter :针对所有路由

全局路由主要处理的实现有(这些实现百度有):

微服务注册Nacos注册的IP却是内网IP 微服务注册中心的组件_spring_05

以上配置全部在下面的案例中体现,参考修改即可:

案例(基于Hystix案例进行修改添加,从头搭建环境太繁琐):

在parent下新建网关模块:

模块依赖:

<dependencies>    <!--引入gateway 网关-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- eureka-客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

Getway的配置:

server:  port: 80

spring:
  application:
    name: Gateway_API

  cloud:
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: # 参数是一个集合。
        # id: 唯一标识。默认是一个UUID,一般设置为节点服务的name
        # uri: 转发服务提供者的访问路径
        # predicates: 条件集合,用于请求网关路径的匹配规则,就是该路径下的某个处理器(具体到某个方法)
        # filters:配置局部过滤器的

        - id: provider
          # 静态路由:直接写死的服务提供方的路径
          # uri: http://localhost:8002
          # 动态路由:从EurekaServer上获取的路经,PROVIDER是服务提供方的EurekaServer上注册的name,必须大写
          uri: lb://ROVIDER
          predicates: #/student/路径下的某个处理器
            - Path=/find/**
          #filters: #集合参数,局部过滤器,实现一系列的前置后置的处理
          #  - AddRequestParameter=username,zhangsan  #参数username赋值张三

        - id: consumer
          # uri: http://localhost:8001
          uri: lb://CONSUMER
          predicates:
            - Path=/consumer/**

          # 微服务名称配置:开启后必须配置服务的名称:http://localhost/服务的名字/consumer/feign//2
      discovery:
        locator:
          enabled: true # 服务名字必须为大写:http://localhost/CONSUMER/consumer/feign//2
          #lower-case-service-id: true # 服务名字必须小写:http://localhost/consumer/consumer/feign//2


##注册到EurekaServer上获取相关的路径端口信息
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eurekaq

全局过滤器(实现接口GlobalFilter, Ordered,并且让ioc容器识别): 

/**
 * 配置全局过滤器:无需任何配置,完成编码会自动识别
 * 需要被ioc识别
 */
@Component
public class Filter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * 做全局的相关操作
         */
        //处理完相应的业务需要放行
        return chain.filter(exchange);
    }

    /**
     * 排序
     * @return 返回数字越小会先执行
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

启动类:

@EnableEurekaClient
@SpringBootApplication
public class GatewayApp {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApp.class,args);
    }
}

其他模块不需要做改动:

然后就可以通过网关访问微服务:

如路径:http://localhost/PROVIDER/find/2,http://localhost/consumer/feign//2

全局过滤器的添加是一个重量级的操作,添加局部过滤器参考官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#_gatewayfilter_factories

自备参考文档:链接:https://pan.baidu.com/s/1OaboaCoK8u608JQEh0LpJg 
提取码:myname

9 SpringCloud的配置文档Config(从这开始就偏向运维了):

概述:这个组件主要是动态的更新各个微服务的配置文件用的,但是只单纯的使用这个去更新配置文件比较的繁琐,还需要结合bus(中间需要mq搭配)组件一起进行配置文件的更新!!!

这些他喵的都是为运维服务的!若是没有明确的要求,一般搭建微服务实在是懒得弄这个,配置文件太烦太烦,多还繁琐...................烦死了!

实现原理,搭建git仓库,然后在微服中搭建一个ConfigServer(pom3)服务,将git仓库绑定到ConfigServer,将该服务注册到EurekaServer上(EurekaClient依赖)!然后在各个需要动态更新配置文件的微服务上引入ConfigClient(pom1),同时需要添加SpringBoot的健康监控组件(pom2),在获取配置文件数据的类上添加@RefreshScope注解,开启动态刷新,其实核心还是使用Spring的健康监控!

刷新哪个微服务执行哪个微服务的请求,例如: http://localhost:8001/actuator/refresh       

上面的 这个请求链接的只用根据项目改主机和端口,使用post发起请求即可(postman或者使用命令:curl -X POST http://localhost:8001/actuator/refresh )

pom1:

<!--config client --><dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

pom2:

<dependency>    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

pom3:

<!-- config-server --><dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

配置文件参考,ConfigServer的配置文件名字为bootstrap,yml(这个名字的配置文件居然他喵的优先于application.*的配置文件):具体的配置参考百度吧,有点烦,用到了去百度吧!!!!!一般这个轮不到我配置,除非真他喵的没人了!太多了,记不住了,也不想整理这块的啦,

最主要的是知道这个东西干嘛的,大概咋用,百度贼多!!!!

10  SpringCloud的bus:

简述:其实就是为了解决使用Config每次更新配置文件还需要去每个微服务都执行请求刷新,实现原理其实就是mq,通过发送刷新命令到mq消息队列实现刷新呗!

11 SpringCloud的Stream:

简述:构建消息驱动微服务...........还是开发无感知的........

12SpringCloud的Sleuth+Zipkin:

简述:sleuth负责收集微服务请求链的相关参数(主要还是效率检测),Zipkin负责将前者收集的数据做web控制台的展示,还是服务运维的...

具体搭建,百度吧!好像只是jar包,跑起来就行!微服务需要导入相关坐标!

前面的案例代码包:链接:https://pan.baidu.com/s/1eyt9UX_rq_iTZ4b-FKJHrQ 
提取码:MyReallyName