springcloud第三天 Feign + Gateway

403 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

Feign

介绍:Feign是一个http请求的轻量级别的框架,在cloud中又有“伪装”。

1. 远程调用

步骤:

  • 创建consumer-service-feign模块

    • web/lombok/eureka-client/openfeign
  • 在启动类添加

    • eurekaclient注解
    • 开启feign支持
  • 编写配置文件

    • 复制consumer-service配置文件,建议修服务的应用名称
  • 编写controller、service接口完成调用

  • 测试

过程:

  • 启动类注解

    @SpringBootApplication
    @EnableEurekaClient //注册到注册中心
    @EnableFeignClients //开启feign支持
    public class ConsumerServiceFeignApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerServiceFeignApplication.class, args);
        }
    }
    ​
    
  • 业务代码

    @RestController
    @RequestMapping("consumer")
    public class ConsumerController {
    ​
        @Autowired
        private ConsumerService consumerService;
        /**
         * @Author: guodong 
         * @Date: 9:52 2020/9/21
         * @Parms [id]
         * @ReturnType: com.itheima.pojo.User
         * @Description: 根据id查找用户
        */
        @GetMapping("findUserById/{id}")
        public User findUserById(@PathVariable Integer id){
            return consumerService.findUserById(id);
        }
    }
    ​
    @FeignClient("user-service")
    public interface ConsumerService {
        /**
         * @Author: guodong
         * @Date: 9:52 2020/9/21
         * @Parms [id]
         * @ReturnType: com.itheima.pojo.User
         * @Description: 根据id查找用户
         *  String url = "http://user-service/user/findUserById/" + id;
         *  注意事项:
         *      1.feign在使用PathVariable注解时必须显示的声明参数,否则异常
         */
        @GetMapping("user/findUserById/{id}")
        User findUserById(@PathVariable("id") Integer id);
    }
    
  • 在测试的过程中发现feign具备了ribbon的功能

image-20200921100340094.png

2. 熔断支持

步骤:

  1. 在配置文件中开启熔断器支持
  2. 编写service的实现类

过程:

  • 配置文件开启支持

    #开启熔断器支持
    feign:
      hystrix:
        enabled: true
    
  • 实现类

    @Component
    public class ConsumerServiceImpl implements ConsumerService {
    ​
        /*
            服务降级方法
         */
        @Override
        public User findUserById(Integer id) {
            User user = new User();
            user.setId(id);
            user.setNote("服务繁忙,请您稍后再试...");
            return user;
        }
    }
    
  • 在service中声明服务降级的类字节码

    @FeignClient(value = "user-service",fallback = ConsumerServiceImpl.class)
    public interface ConsumerService {
        /**
         * @Author: guodong
         * @Date: 9:52 2020/9/21
         * @Parms [id]
         * @ReturnType: com.itheima.pojo.User
         * @Description: 根据id查找用户
         *  String url = "http://user-service/user/findUserById/" + id;
         *  注意事项:
         *      1.feign在使用PathVariable注解时必须显示的声明参数,否则异常
         */
        @GetMapping("user/findUserById/{id}")
        User findUserById(@PathVariable("id") Integer id);
    }
    
3. 日志配置

image-20200921101934276.png

步骤:

  1. 在配置文件中声明日志级别(info/debug/error)
  2. 编写feign日志配置类
  3. 在service中配置feign日志配置类的class字节码(经测试,可以不配置也会生效)

过程:

  • 配置文件声明日志级别

    #日志级别配置
    logging:
      level:
        com.itheima: debug
    
  • feign配置类

    @Configuration //声明是一个配置类
    public class FeignLogConfig {
    ​
        /*
            logger注意导包---》 import feign.Logger;
         */
        @Bean
        public Logger.Level configLog(){
            return Logger.Level.FULL;
        }
    }
    

二、Gateway

介绍:网关系统,路由(负载)+鉴权。是用于替换zuul(网关),gateway是cloud自己全新的组件。

image-20200921105821159.png

1. 网关搭建

步骤:

  1. 创建gateway-service服务

    • eureka-client
    • gateway
  2. 配置文件

    • 复制配置文件---》修改应用名称
  3. 在启动类添加注解

    • eurekaclient注解

过程:

  • 配置文件

    server:
      port: 10010
    spring:
      application:
        name: gateway-server
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    
  • 启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class GatewayServerApplication {
    ​
        public static void main(String[] args) {
            SpringApplication.run(GatewayServerApplication.class, args);
        }
    ​
    }
    
  • 注意事项:

    • 千万不要选择web依赖,gateway启动时使用的是webful。
2. 网关路由
  • 配置文件

    server:
      port: 10010
    spring:
      application:
        name: gateway-server
      cloud:
        gateway:
          routes:
            - id: consumer-service-feign-route
              uri: http://localhost:8081
              predicates:
                - Path=/**
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    

    存在问题uri硬编码需要写活------》动态。

3. 动态路由

步骤:

  1. 创建两个消费者的启动类

  2. 修改网关配置文件

    server:
      port: 10010
    spring:
      application:
        name: gateway-server
      cloud:
        gateway:
          routes:
            - id: consumer-service-feign-route
            #动态路由通过lb协议可以根据服务的应用名称将服务列表从注册中心获取到本地,然后通过ribbon进行负载
              uri: lb://consumer-service-feign #http://localhost:8081
              predicates:
                - Path=/**
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    
4. 路由前缀
5. 过滤器

image-20200821083117676.png

server:
  port: 10010
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: consumer-service-feign-route
        #动态路由通过lb协议可以根据服务的应用名称将服务列表从注册中心获取到本地,然后通过ribbon进行负载
          uri: lb://consumer-service-feign #http://localhost:8081
          predicates:
            - Path=/**
          filters:
            #添加前缀
            - PrefixPath=/consumer
            #去除前缀
            - StripPrefix=1
      #全局过滤器添加响应头
      default-filters:
        - AddResponseHeader=i-love,itheima
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
6. 自定义过滤器

需求:

判断用户是否有登录?通过token令牌? 从请求数据中获取token参数,判断是否为空?

步骤:

  1. 创建类实现全局过滤器,Ordered接口

    • 重写filter方法

      • 获取请求对象
      • 从请求对象中获取请求参数token
      • 对token进行判空校验
      • 如果为空拦截
      • 如果不为空放行
    • order方法

      • 过滤器优先级别---》数值越小优先级别越高
  2. 返回

过程:

  • @Component
    public class MyFilter implements GlobalFilter,Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            //- 获取请求对象
            ServerHttpRequest request = exchange.getRequest();
            //- 从请求对象中获取请求参数token
            String token = request.getQueryParams().getFirst("token");
            //- 对token进行判空校验
            if(StringUtils.isEmpty(token)){ //token为空
                //- 如果为空拦截
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.UNAUTHORIZED); //401表示无权限访问
                //编译返回
                return response.setComplete();
            }
            //- 如果不为空放行
            return chain.filter(exchange);
        }
    ​
        /**
         * @Author: guodong 
         * @Date: 12:16 2020/9/21
         * @Parms []
         * @ReturnType: int
         * @Description: 值越小优先级越高,建议值要小于2,因为路由也是一个过滤器,并且路由过滤器的优先级别为2
        */
        @Override
        public int getOrder() {
            return 0;
        }
    }
    ​
    
  • http://localhost:10010/consumer/findUserById/2?token=121546456485