SpringCloud微服务项目快速搭建(二)(SpringCloud Netflix,H版-SR3)

一、概述

1.什么是OpenFeign

        OpenFeign是一个声明性的Web服务客户端,它使得编写Web服务客户端变得更加容易。OpenFeign使用基于注解的方法定义请求接口,并且自动地处理了请求参数处理、编码、解码和错误处理。它是一个轻量级的库,可以与其他Java库和框架集成使用,例如Spring Cloud。OpenFeign的目标是简化HTTP API的调用,并为微服务架构提供一致的客户端体验。

2.什么是Hystrix

        Hystrix是一个开源的延迟和容错库,由Netflix开发并维护。它旨在通过隔离服务之间的访问点、停止级联故障,以及提供备选响应来改进分布式系统的容错能力。

2.1.Hystrix具有的以下功能

        1.服务熔断:如果检测到服务不可用那么会触发服务熔断,也就是断开跟服务的连接。

        2.服务降级:当服务掉不通的时候,不是一个报错所以不应该触发全局异常,那么此时我们应该给一个托底数据/友好提示,响应给用户。

        3.服务限流/资源隔离:限制服务只能进入多少请求,超过设置的数量的请求进行排队,这是为了防止突然的大流量冲垮服务。

        4.缓存:Hystrix会帮我们缓存请求的数据,如果下次还是这个请求那么直接响应。

        4.Hystrix熔断触发规则

                1.服务调不通会触发

                2.服务调用慢超时会触发

                3.服务报错也会触发

3.什么是Zuul,为什么需要

        在微服务架构中,服务之间的协作是非常复杂和困难的,主要涉及路由、过滤、负载均衡、缓存、安全认证等多个方面。这时就需要一个中间层来处理这些问题,而Zuul就是这样一个API网关中间件,它通过反向代理和负载均衡等技术,为服务提供者和服务消费者之间提供路由、过滤、安全认证、监控等功能,从而实现了微服务的可靠和高效运行。

扫描二维码关注公众号,回复: 16406973 查看本文章

二、OpenFeign的使用

1.导入依赖

  <!--引入OpenFeign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.启动类加注解@EnableFeignClients

3.创建feign接口,规范在feign包下

package com.lzc.feign;

import com.lzc.domain.User;
import com.lzc.fallback.UserFeignClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

// contextId FeignClient的唯一标识,推荐类名小驼峰
// path 映射路径 也可以requestMapping写在类上
// value 服务名称
@FeignClient(contextId = "userFeignClient",path = "user",value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
    @GetMapping
    User getUser();
}

4.在需要调用的地方注入使用

package com.lzc.controller;

import com.lzc.domain.User;
import com.lzc.feign.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/pay")
public class PayController {
    @Autowired
    private UserFeignClient userFeignClient;
    @GetMapping
    public User getUser(){
      return userFeignClient.getUser();
    }
}

三、Hystrix的使用

1.Hystrix可以通过以下几种方式与其他的框架或者库进行整合:

        1. Hystrix和Spring Cloud整合:Hystrix和Spring Cloud结合是最常见,也是最简单的整合方式。Spring Cloud为Hystrix提供了自动化的配置和属性管理,大大简化了Hystrix的使用和部署过程。Spring Cloud还提供了Dashboard来可视化监控Hystrix命令的指标和熔断状态,方便快捷地进行故障排查和性能调优。

        2. Hystrix和Netflix Eureka整合:Netflix Eureka是一种服务发现框架,可以使得服务消费者可以直接从Eureka Server注册中心获取服务提供者的地址信息。通过将Hystrix和Eureka结合,我们可以很容易地实现服务的自动熔断和自动容错,提高整个分布式系统的可用性和鲁棒性。

        3. Hystrix和Ribbon整合:Ribbon是一种负载均衡框架,可以使得服务消费者可以通过负载均衡的方式调用服务提供者。通过将Hystrix和Ribbon结合,我们可以很容易地实现服务的高可用和高性能,从而提高整个分布式系统的稳定性和可靠性。

        4. Hystrix和Zuul整合:Zuul是一种API网关,可以为服务提供者和服务消费者之间提供路由和过滤。通过将Hystrix和Zuul结合,我们可以很容易地实现服务的自动熔断和自动容错,以及API网关的功能,从而提高整个分布式系统的可用性和鲁棒性。

我们可以通常总结为

        1.Ribbon整合Hystrix(了解)

                1.方法独立降级:每个controller接口写一个降级方法

                2.统一降级方法:整个类的所有方法用一个降级方法,但是要注意所有方法的返回值必须一致

        2.OpenFeign整合Hystrix

                1.普通降级

                2.工厂降级-重点掌握

2.浅用Ribbon整合Hystrix

1.导入依赖

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

2.启动类加注解@EnableCircuitBreaker

3.方法加注解@HystrixCommand(fallbackMethod = "getUserFallbackMethod")

package com.lzc.controller;

import com.lzc.domain.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;


// RestTemplate没加负载均衡的
//    @GetMapping
//    public User getUser(){
//        User user = restTemplate.getForObject("http://localhost:1020/user", User.class);
//        return user;
//    }

    // 开启RestTemplate负载均衡
    @GetMapping
    @HystrixCommand(fallbackMethod = "getUserFallbackMethod")
    public User getUser(){
        log.info("进入了getUser.........");
        return restTemplate.getForObject("http://user-server/user", User.class);
    }

    public User getUserFallbackMethod(){
        log.info("进入了getUserFallbackMethod......");
        return new User(-1L,"熔断了.......");
    }
}

3.OpenFeign整合Hystrix

1.导入依赖

    <!--引入OpenFeign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.@FeignClient(contextId = "userFeignClient",path = "user",value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)加上fallbackFactory=“”

3.创建UserFeignClientFallbackFactory类

package com.lzc.fallback;


import com.lzc.domain.User;
import com.lzc.feign.UserFeignClient;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {


    @Override
    public UserFeignClient create(Throwable throwable) {
        return new UserFeignClient() {
            @Override
            public User getUser() {
                log.info("我进feign的托底方法了........");
                return new User(-2L,"熔断了.......");
            }
        };
    }
}

4.整合Zuul

1.导入依赖

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

2.启动类加上注解@EnableZuulProxy,开启Zuul服务支持

3.配置yml

server:
  port: 1050 # 服务端口号

eureka:
  client: # Eureka客户端配置,指向注册中心地址
    serviceUrl:
      defaultZone: http://localhost:1010/eureka/
  instance:
    prefer-ip-address: true # 开启使用IP地址进行注册
    instance-id: zuul-server:1050 # 修改实例Id
spring:
  application: # 指定此服务的应用名称
    name: zuul-server


zuul:
  prefix: "/apis"  #统一访问前缀
  ignoredServices: "*"  #禁用掉使用浏览器通过服务名的方式访问服务
  routes:
    pay-server: "/pay/**"   #指定pay-server这个服务使用 /pay路径来访问  - 别名
    order-server: "/order/**"   #指定order-server这个服务使用 /order路径来访问

4.1自定义Zuul的filter

        Zuul的底层是通过各种Filter来实现的,Zuul中的Filter按照执行顺序分为了以下几种,当各种Filter出现了异常,请求会跳转到ErrorFilter,然后再经过PostFilter,最后返回结果,如果是PostFilter出现异常,那么也会走ErrorFilter,然后直接响应。

1.自定义拦截器,通过继承ZuulFilter

package com.lzc.fallback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;


@Component
public class PayServerFallback implements FallbackProvider {
    // 得到日志对象
    private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
    @Override
    public String getRoute() {
        return "pay-server";  //"*"代表所有服务都有作用
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 0;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("抱歉,服务不可用".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

 2.Zuul的熔断配置

package com.lzc.fallback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;


@Component
public class PayServerFallback implements FallbackProvider {
    // 得到日志对象
    private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
    @Override
    public String getRoute() {
        return "pay-server";  //"*"代表所有服务都有作用
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 0;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("抱歉,服务不可用".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

猜你喜欢

转载自blog.csdn.net/lzc19991201/article/details/131271391