SpringCloud

SpringCloud引言

单体all in on --> 微服务模块化(代码没变化~)

        Spring(IOC AOP) -- 简化开发 
        SpringBoot        --   自动装配 (专注于快速、方便开发单个微服务)
        SpringCloud       --   解耦合 (关注全局的微服务协调治理框架,他将单体微服务整合并管理)

微服务:单体(单一)应用-->模块化拆分若干服务,每个服务围绕具体业务构建,服务之间相互协调,互相配置,独立部署
        核心就是将传统的一站式应用,根据业务拆分一个个服务(独立处理,独立数据库),彻底解耦合


        

Spring Cloud Netflix 组件(五大神兽)

通用使用步骤:

    1.导入依赖
    2.编写配置文件 yml|properties
    3.开启功能
    4.编写配置类

一、Eureka 服务注册与发现

1、Eureka(服务注册中心)

          基于Rest服务,用于定位服务

(1)Eureka自我保护机制--不推荐关闭自我保护机制

     微服务不能用,eureka不会立即清理,依旧会保存该微服务的信息
          默认90内未接收到微服务实例的心跳


(2)设计理念

         宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例
          

(3)对比zookeeper

         分布式数据库:Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性),三者不能同时成立

         Zookeeper:C一致性+P容错性;Eureka:A可用性+P容错性

         Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪

(4)代码实战

 (1)配置服务注册中心 ---->>  Eureka Server

      a 导入依赖

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka-server</artifactId>
   <version>1.4.6.RELEASE</version>
</dependency>

      b 配置yaml

server:
  port: 7001
      
#Eureka 配置
eureka:
  instance:
    hostname: eureka7001.com #Eureka服务端实例名称
  client:
    register-with-eureka: false #表示自己就是注册中心,不用注册自己
    fetch-registry: false      #表示自己就是注册中心,不用去注册中心获取其他服务的地址
    service-url:
      #单机配置
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群配置,除当前注册中心外,配置其他注册中心,共同组建集群!
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#  server:
#    enable-self-preservation: false #禁用自我保护机制[不推荐]

    开启服务(主启动类)

@EnableEurekaServer //服务端启动类,可以接受别人注册

    (二)服务注册 ---->>  Server Provider

     新建module [springcloud-api] 准备实体类 Dept

查看代码
@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
public class Dept implements Serializable {// dept 实体类 orm 类表关系映射

    private Long deptno;
    private String dname;

    //这个数据库存在哪个数据库的字段~,微服务,一个服务对应一个微服务,同一信息可能存在不同的数据库
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }

    /*
        链式写法:
            Depte dept = new Dept();
            dept.setDeptNo(11);
            dept.set..;
          new Dept().setDeptNo(11).setDname('333').setDb_source('001');
     */
}

     新建服务module [springcloud-provider-dept-8001]

     a 导入pom依赖    

查看代码
<!--我们需要拿到实体类,所以要配置api module-->
        <dependency>
            <groupId>com.nercita</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--Eureka 客户端配置-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--actuator 完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!--日志测试~-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <!--SpringBoot 启动器-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>0.2.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--springCloud的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--SpringBoot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

      b 编写yaml配置

      

查看代码
server:
  port: 8001
  
#mybatis配置
mybatis:
  type-aliases-package: com.nercita.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

#spring配置
spring:
  application:
    name: springcloud-provider-dept #三个服务名称一致,实例不同
  datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: org.gjt.mm.mysql.Driver
      url: jdbc:mysql://localhost:3306/bcp?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
      username: root
      password: root

#Eureka配置 :服务注册到哪里
eureka:
  client:
    service-url:
      #注册到单机服务器
#      defaultZone: http://localhost:7001/eureka/
      #注册到集群服务器,将服务注册到这里
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001
#配置info 可以看到微服务备注 -- json字符串响应
info:
    app.name: nercita-springcloud
    company.name: nercita.com

c 完善服务请求接口和对应mybatis接口以及对应的 Mapper.xml 文件配置

查看代码
//提供Restful服务
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @Autowired
    private DiscoveryClient client;

    //只允许post方式提交,默认浏览器请求属于get请求
    @PostMapping("/deptAdd")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/deptGetById/{id}")
    public Dept queryById(@PathVariable("id") Long id){
        Dept dept = deptService.queryDeptById(id);
        if(dept == null){
            throw new RuntimeException("id=>"+id+",不存在该用户或信息无法找到");
        }
        return dept;
    }

    @GetMapping("/deptGetAll")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }

    //注册进来的微服务,获取一些消息 -- 联合开发
    @GetMapping("/deptDiscovery")
    public Object discovery(){
        List<String> services = client.getServices();
        System.out.println("discover=>service:"+services);

        //得到具体一个微服务信息 -- applicationName
        List<ServiceInstance> instances = client.getInstances("springcloud-provider-dept");
        for (ServiceInstance instance : instances) {
            System.out.println(
                instance.getHost()+"\t"+  //springcloud-provider-dept8001
                instance.getInstanceId()+"\t"+ //springcloud-provider-dept8001
                instance.getUri()+"\t"+ //http://windows10.microdone.cn:8001
                instance.getServiceId() //SPRINGCLOUD-PROVIDER-DEPT
            );
        }
        return this.client;
    }
}

    (三)服务消费 ---->>  Service Consumer

      新建module [springcloud-consumer-dept-80]

      a 导入依赖     

<!--消费者不需要连接数据库,需要实体类+web-->
    <dependencies>
        <dependency>
            <groupId>com.nercita</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <!--1.导入ribbon依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--1.导入Eureka依赖 客户端配置-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

    </dependencies>

     b 编写yaml配置

server:
  port: 80

#Eureka配置
eureka:
  client:
    #不向eureka中注册自己
    register-with-eureka: false
    service-url:
      #集群注册服务,从这里取服务
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

  c 开启功能(主启动类)

@EnableEurekaClient //3.开启服务

 d 编写请求Controller(通过ip:port请求注册中心的服务

查看代码
//消费者不应该有service
@Controller
public class DeptConsumerController {

    /*
        springboot支持:restful -- RestTemplate ..供我们直接调用就可以了!注册到Spring中
          三个参数:  url,实体 map,responseType

        restTemplate :提供多种便捷访问远程http服务的方法,简单的RestFul服务模板(spring提供)
     */
    @Autowired
    private RestTemplate restTemplate;

    /*
        注意:使用ribbon负载均衡是,访问的ip地址应该是一个变量,通过服务名来访问serviceId
     */
    private static final String REST_URL_PREFIX="http://localhost:8001";
//    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

    @RequestMapping("/consumergetDeptById/{id}")
    @ResponseBody
    public Dept getDept(@PathVariable("id") Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/deptGetById/"+id,Dept.class);
    }

    @RequestMapping("/consumergetAllDept")
    @ResponseBody
    public List<Dept> getAllDept(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/deptGetAll",List.class);
    }

    @RequestMapping("/consumerAddDept")
    @ResponseBody
    public boolean addDept(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/deptAdd",dept,Boolean.class);
    }

}

二、Ribbon|Feign 负载均衡 (基于客户端配置)

目的:将用户请求平摊分配多个服务上,达到系统的高可用

1、请求url

ribbon负载均衡:访问的ip地址应该是一个变量,通过服务名来访问serviceId 【服务名代替ip+端口号】

客户端可以直接调用,不用关心ip地址和端口号:即localhost:80/consumergetDeptById/1

即yml配置文件:

spring:
  application:
    name: springcloud-provider-dept #三个服务名称一致,实例不同

代码配置: private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT" 

客户端可以直接调用,不用关心ip地址和端口号

2、负载均衡策略

  (1)调用负载均衡策略

 IRule
  AbstractLoadBalancerRule
    RetryRule 重试
    RandomRule 随机
    RoundRobinRule 轮询 (默认)
        WeightedResponseTimeRule 权重
    ClientConfigEnabledRoundRobinRule
        PredicateBasedRule
            AvailabilityFilteringRule 过滤掉故障的服务,对剩下的进行轮询

(2)自定义负载均衡策略

自定义规则

@Configuration
public class MyRule extends AbstractLoadBalancerRule {

    private int total=0;//被调用次数
    private int currentIndex=0;//当前服务位置

    public MyRule() {
    }

    /*
        每个服务访问5次换下一个服务
        默认total=0,total=5指向下一个服务节点
        默认index=0,total=5 index++;
     */
//    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            Server server = null;

            while(server == null) {
                if (Thread.interrupted()) {
                    return null;
                }

                List<Server> upList = lb.getReachableServers();//获取活着的服务
                List<Server> allList = lb.getAllServers();//获取全部的服务
                int serverCount = allList.size();
                if (serverCount == 0) {
                    return null;
                }

                //算法
//                int index = this.chooseRandomInt(serverCount);//生成区间随机数
//                server = (Server)upList.get(index);//从或者的服务中随机获取一个

                //自定义算法
                if(total<5){
                    server = (Server)upList.get(currentIndex);//从或者的服务中随机获取一个
                    total++;
                }else{
                    total=0;
                    currentIndex++;
                    if(currentIndex>=upList.size()){
                        currentIndex=0;
                    }
                    server = upList.get(currentIndex);
                }

                if (server == null) {
                    Thread.yield();//线程礼让
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();//线程礼让
                }
            }

            return server;
        }
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

a 依赖导入

         <!--1.导入ribbon依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

b JavaConfig 注册bean

实现方式一
@Configuration // @Configuration -- spring applicationContext.xml
public class ConfigBean {

    /*
    IRule
    AbstractLoadBalancerRule
        RetryRule 重试
        RandomRule 随机
        RoundRobinRule 轮询 (默认)
            WeightedResponseTimeRule 权重
        ClientConfigEnabledRoundRobinRule
            PredicateBasedRule
                AvailabilityFilteringRule 过滤掉故障的服务,对剩下的进行轮询
     */
    @Bean
    //配置负载均衡 实现RestTemplate
    @LoadBalanced //Ribbon
    //springboot支持:restful -- RestTemplate ..供我们直接调用就可以了!注册到Spring中
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    //切换负载均衡策略,这个与自定义的配置文件MyRuleConfig只能开启一个
    @Bean
    public IRule RandomRule(){ //名字可以自定义
        return new MyRule();//自定义实现,或者换成其他自带负载均衡策略
    }

}

b2 开启服务来注册bean

 主启动类:

@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRuleConfig.class)

javaConfig注册bean:

@Configuration
public class MyRuleConfig {

    @Bean
    public IRule myRule(){
        return new MyRule();
    }

}

3、区别对比Nginx

(1)Nginx是常见负载均衡软件;Ribbon是客户端负载均衡工具

(2)Nginx是集中式负载均衡LB;Ribbon是进程式负载均衡LB,负载均衡逻辑集成到消费方,消费方从服务注册中心获知哪些地址可用,从中选取负载均衡合适服务器

4、区别对比Feign

Feign 是在 Ribbon 的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方法即可, 不需要自己构建 http 请求。然后就像是调用自身工程的方法调用,而感觉不到是调用远程方法,使得编写客户端变得非常容易。

Ribbon 是一个基于 HTTP 和 TCP 客户端 的负载均衡的工具。它可以 在客户端 配置 RibbonServerList(服务端列表),使用 HttpClient 或 RestTemplate 模拟 http 请求,

(1)启动类使用的注解不同,Ribbon 用的是@RibbonClient,Feign 用的是@EnableFeignClients
(2)服务的指定位置不同,Ribbon 是在@RibbonClient 注解上声明规则类,Feign 则是在定义抽象方法的接口中使用@FeignClient 声明。

#主启动类上添加注解
@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRuleConfig.class)
#业务层接口上添加注解
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)

(3)调用方式不同,Ribbon 需要自己构建 http 请求,模拟 http 请求然后使用 RestTemplate 发送给其他服务,步骤相当繁琐。Feign把RestTemplate封装起来,加了一层效率变低,可读性提高。

5、Feign代码

(1)导入依赖

<!--1.导入feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

(2)配置yml

server:
  port: 80


#Eureka配置
eureka:
  client:
    #不向eureka中注册自己
    register-with-eureka: false
    service-url:
      #集群注册服务
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#开启服务降级feign.hystrix
feign:
  hystrix:
    enabled: true

(3)开启服务(主启动类)

@EnableFeignClients(basePackages = {"com.nercita.springcloud"})

(4)配置业务接口

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @PostMapping("/deptAdd")
    public boolean addDept(Dept dept);

    @GetMapping("/deptGetById/{id}")
    public Dept queryDeptById(@PathVariable("id") Long id);

    @GetMapping("/deptGetAll")
    public List<Dept> queryAll();

}

(5)controller请求并调用service方法

三、Hystrix 熔断、降级、流监控

1、分布式系统面临的问题(1)及解决方案(2)(3)

服务熔断和服务降级就可以视为解决服务雪崩的手段之一

(1)服务雪崩

原因:多个微服务之间调用的时候,假设A调用B和C,BC调用其他(这一条调用链叫扇出)。 如果扇出链路行某个微服务调用响应时间过长或不可用,为微服务A的调用就会扎不会有越来越多的系统资源,引起系统崩溃。

解决方案:限流,限制并发的请求访问量,超过阈值则拒绝或等待;

(2)服务熔断 Hystrix(回调方法)

服务端操作:对应雪崩效应的一种微服务链路保护机制(相当于捕获异常

熔断目的:依赖的下游服务故障触发熔断,避免引发本系统崩溃;系统自动执行和恢复

   a 导入依赖

<!--hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

   b 开启熔断服务 (主启动类)

@EnableCircuitBreaker //3.开启对熔断的支持

  c  请求添加回调方法

@HystrixCommand(fallbackMethod = "hystrixQueryById") //失败后常识调用
//提供Restful服务
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @HystrixCommand(fallbackMethod = "hystrixQueryById") //失败后常识调用
    @GetMapping("/deptGetById/{id}")
    public Dept queryById(@PathVariable("id") Long id){
        Dept dept = deptService.queryDeptById(id);
        if(dept == null){
            throw new RuntimeException("id=>"+id+",不存在该用户或信息无法找到");
        }
        return dept;
    }

    //备选方法
    public Dept hystrixQueryById(@PathVariable("id") Long id){
        return new Dept()
                .setDeptno(id)
                .setDname("id=>"+id+"没有对应的信息,null--@Hystrix")
                .setDb_source("no this database in mysql");
    }


}
//滑动窗口的大小,默认为20
circuitBreaker.requestVolumeThreshold 
//过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟
circuitBreaker.sleepWindowInMilliseconds 
//错误率,默认50%
circuitBreaker.errorThresholdPercentage

5s内,每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。

这些属于框架层级的实现,我们只要实现对应接口就好!

(3)服务降级(回调类)

客户端操作:从整体网站请求负载考虑,当某个服务熔断或关闭之后,服务将不再被调用。客户端可以准备一个自己的失败回调函数FallbackFactory,返回一个默认的缺省值。(相当于404时,返回一个自定义页面

降级目的:服务分优先级,牺牲非核心服务(不可用),保证核心服务稳定;从整体负荷考虑;

#开启服务降级feign.hystrix
feign:
 hystrix:
  enabled: true

@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)

注意事项:

     1、回调函数要继承FallbackFactory类,可以来自于其他组件

     2、接口要保持一致

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)

定义与其他组件的接口
/*
    这里要与consumer-dept-feign接口保持一致
 */
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @PostMapping("/deptAdd")
    public boolean addDept(Dept dept);

    @GetMapping("/deptGetById/{id}")
    public Dept queryDeptById(@PathVariable("id") Long id);

    @GetMapping("/deptGetAll")
    public List<Dept> queryAll();

}

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)

客户端的接口
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @PostMapping("/deptAdd")
    public boolean addDept(Dept dept);

    @GetMapping("/deptGetById/{id}")
    public Dept queryDeptById(@PathVariable("id") Long id);

    @GetMapping("/deptGetAll")
    public List<Dept> queryAll();

}

@Component

定义在其他组件的回调函数方法
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService(){

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }

            @Override
            public Dept queryDeptById(Long id) {
                return new Dept().setDeptno(id)
                        .setDname("id=>>"+id+",没有对应信息,客户端提供降级的信息,这个服务已经关闭")
                        .setDb_source("没有数据");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }
        };
    }
}

总结:

     a 熔断必会触发降级,所以熔断也是降级一种。区别在于熔断是对调用链路的保护,而降级是对系统过载的一种保护处理。

   2、流监控 hystrix.dashboard

    (1)新建module[springcloud-consumer-dashboard]

 (2)导入pom依赖

查看代码
<!--消费者不需要连接数据库,需要实体类+web-->
<dependencies>
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--hystrix.dashboard-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.nercita</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>

    <!--1.导入ribbon依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

    <!--1.导入Eureka依赖 客户端配置-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

</dependencies>

服务端项目配置pom依赖

<!--actuator 完善监控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

     (3)配置yml端口号

server:
  port: 9001

    (4)开启服务(主启动类)

@EnableHystrixDashboard //3.开启服务

服务端项目主启动类配置,注册ServletRegistrationBean对象

@SpringBootApplication
@EnableEurekaClient //3.开启功能:启动Eureka客户端服务
@EnableDiscoveryClient //3.开启服务发现
@EnableCircuitBreaker //3.开启对熔断的支持
public class DeptProvider_hystrix_8001 {

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

    //增加一个servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

 (5)访问:localhost:9001/hystrix

四、Zuul 路由网关 9527

1、什么是Zuul?

目的:隐藏真实地址

       (1)提供代理、路由、过滤三大功能

路由:负责将外部请求转发到uti的微服务实例上,是实现外部访问统一入口的基础。

过滤:负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。

  (2)从注册中发现服务
Zuul和Eureka整合后,自身也注册为Eureka服务治理下的应用,同时从Eureka中获取其他微服务的消息。

即:微服务的访问都是通过Zuul跳转后获得。

2、代码实现

(1)导入pom依赖

<!--zuul-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

(2)配置yml文件

spring:
  application:
    name: springcloud-zuul
zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/** #未实现
#  ignored-services: springcloud-provider-dept #不能访问的路径
#  prefix: /sc #配置统一前置

(3)开启服务(主启动类)

@EnableZuulProxy

五、Config 分布式配置

1、git基础使用

(1)下载、使用

  个人git主页:gitee.com 
  下载:git bash here 
  快捷键:

        ctrl+ins 复制
        shift+ins 粘贴

(2)配置权限

   生成秘钥:ssh-keygen -t rsa -C "1289775791@qq.com"
   复制:用户/administrator/.ssh/id_rsa.pub,复制到git公钥

(3)提交上传

   常用的提交命令:        
        git add . 把当前修改的全部提交到暂存区
        git status
        git commit -m "first commit" #提交本地
        git push origin master #需配置个人公钥,提交git

2、代码项目配置

(1)新建Module【springcloud-config-server3344、springcloud-config-client3355、springcloud-config-eureka7001

(2)分别导入pom依赖

  springcloud-config-server3344

    <dependencies>
        <!--springcloud-config-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--actuator 完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

springcloud-config-client3355

<dependencies>
    <!--springcloud-config-client  starter-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--actuator 完善监控信息-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

springcloud-config-eureka7001

<dependencies>
    <!--springcloud-config-client  starter-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

    <!--热部署工具-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

(3)分别配置yml

springcloud-config-server3344

server:
  port: 3344
spring:
  application:
    name: springcloud-config-server
  #连接远程仓库
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/zzldbl/springcloud-config.git #是http不是git

springcloud-config-client3355

#用户级别的配置 -->配置名字
spring:
  application:
    name: springcloud-config-client-3355
bootstarp
#系统级别的配置 -->配置读谁
spring:
  cloud:
    config:
      uri: http://localhost:3344
      name: config-client #需要从git上读取的资源名称,不需要后缀
      profile: test
      label: master

springcloud-config-eureka7001

 

#用户级别的配置 -->配置名字
spring:
  application:
    name: springcloud-config-eureka-7001
bootstarp
#系统级别的配置 -->配置读谁
spring:
  cloud:
    config:
      name: config-eureka #需要从git上读取的资源名称,不需要后缀
      uri: http://localhost:3344 #指向服务器
      profile: dev #环境
      label: master

(4)开启eureka和service服务,并启动客户端(均为主启动类)

springcloud-config-server3344

@EnableConfigServer

springcloud-config-client3355

springcloud-config-eureka7001

@EnableEurekaServer //服务端启动类,可以接受别人注册

(5)获取git上配置文件的内容并输出

@RestController
public class ConfigClientController {

    /*
        客户端通过服务器获取git服务器的 config-client.yml 配置
        客户端可以选择环境 bootstrap.yml --> profiles:dev/test
     */
    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaService;
    @Value("${server.port}")
    private String port;


    @RequestMapping("/config")
    public String getConfig(){
        String str = "applicationName:"+applicationName+",eurekaServer:"+eurekaService+",port:"+port;
        return str;
    }
}
posted @ 2022-04-22 18:36  小吴dnd  阅读(59)  评论(0编辑  收藏  举报