SpringCloud

1. 微服务应用场景

创建父工程spring-cloud,依赖如下

<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.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <gson.version>2.8.0</gson.version>
    <jackson.version>2.9.5</jackson.version>
    <swagger.version>2.9.2</swagger.version>
    <mybatis.plus.boot.version>3.1.0</mybatis.plus.boot.version>
    <hutool.version>5.3.4</hutool.version>
    <druid.version>1.1.10</druid.version>
</properties>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>${hutool.version}</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

1.1 创建服务提供者

springcloud-provider

添加依赖

    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>${mybatis.plus.boot.version}</version>
    </dependency>
    <!--druid-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>${druid.version}</version>
    </dependency>

    <!--mybatis逆向生成-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.1.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.0</version>
        <scope>test</scope>
    </dependency>

配置application.yml

server:
  port: 8081
spring:
  application:
    name: provider
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://192.168.100.101:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
      username: root
      password: 123456

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml # mapper映射文件的路径
  type-aliases-package: com.iweb.model
  global-config:
    db-config:
      id-type: id_worker # 分布式全局唯一id
  configuration:
    map-underscore-to-camel-case: false # 驼峰是否转下划线
    cache-enabled: true # 全局缓存开关
    lazy-loading-enabled: true # 延迟加载
    multiple-result-sets-enabled: true # 开启延时加载,否则按需加载 属性
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql语句

通过mybatis-plus直接生成

public class MyBatisGenerate {

    @Test
    public void generate() {
        //
        String url = "jdbc:mysql://192.168.100.101:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull";
        // 基本包
        String parentPackage = "com.iweb";
        String baseDir = System.getProperty("user.dir");
        String driverClassName = "com.mysql.cj.jdbc.Driver";
        String username = "root";
        String password = "123456";

        // 表 前缀
        String[] tablePrefix = new String[]{"tb_"};
        String[] tableNames = new String[]{"tb_user"};

        /*数据源*/
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setUrl(url);
        dsc.setDriverName(driverClassName);
        dsc.setUsername(username);
        dsc.setPassword(password);

        /*全局配置*/
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(baseDir + "/src/main/java");
        gc.setFileOverride(true);
        gc.setActiveRecord(true);
        gc.setEnableCache(false);// XML 二级缓存
        gc.setBaseResultMap(true);// XML ResultMap
        gc.setBaseColumnList(true);// XML columList
        gc.setAuthor("jack");
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");

        /*生成策略*/
        StrategyConfig strategy = new StrategyConfig();
        strategy.setEntityLombokModel(true);
        strategy.setEntityTableFieldAnnotationEnable(true);
        strategy.setTablePrefix(tablePrefix);// 此处可以修改为您的表前缀
        strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
        strategy.setInclude(tableNames); // 需要生成的表

        /*生成文件包配置*/
        PackageConfig pc = new PackageConfig();
        pc.setParent(parentPackage);
        pc.setController("controller");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setEntity("model");
        pc.setMapper("mapper");

        AutoGenerator mpg = new AutoGenerator();

        /*xml文件配置*/
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // nothing
            }
        };
        //xml生成路径
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return baseDir + "/src/main/resources/" + "/mapper/" + tableInfo.getEntityName() + "Mapper.xml";
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 关闭默认 xml 生成,调整生成 至 根目录
        TemplateConfig tc = new TemplateConfig();
        tc.setXml(null);

        mpg.setDataSource(dsc);         //数据源配置
        mpg.setGlobalConfig(gc);        //全局配置
        mpg.setStrategy(strategy);      //生成策略配置
        mpg.setPackageInfo(pc);         //包配置
        mpg.setCfg(cfg);                //xml配置
        mpg.setTemplate(tc);            //
        // 执行生成
        mpg.execute();
    }

}

完成Controller

@RequestMapping("/user")
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> findAll() {
        return userService.list();
    }

    @GetMapping("{id}")
    public User findById(@PathVariable Long id) {
        return userService.getById(id);
    }
}

1.2 创建服务消费者

springcloud-consumer

添加依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-annotation</artifactId>
        <version>3.1.0</version>
        <scope>compile</scope>
    </dependency>

配置application.yml

server:
  port: 8082
spring:
  application:
    name: consumer

完成 ConsumerController

@RequestMapping("/consumer")
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping
    private List<User> findAll() {
        String url = "http://localhost:8081/user";
        return restTemplate.getForObject(url, List.class);
    }

}

通过消费者向提供者请求数据:http://127.0.0.1:8082/consumer

2. 注册中心 Spring Cloud Eureka

2.1 创建注册中心

springcloud-eureka

2.2 注册提供者到注册中心

添加依赖

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

修改application.yml配置文件

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

将微服务注册到注册中心

@EnableDiscoveryClient // 注册到注册中心
@SpringBootApplication
@MapperScan(value = "com.iweb.mapper")
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class);
    }
}

在Eureka监控页面可以看到服务注册成功信息

2.3 注册消费者到注册中心

添加依赖

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

修改application.yml配置文件

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

将微服务注册到注册中心

@EnableDiscoveryClient // 注册到注册中心
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

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

2.4 通过注册中心访问提供者

@RequestMapping("/consumer")
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping
    private List<User> findAll() {
//        String url = "http://localhost:8081/user";
//        return restTemplate.getForObject(url, List.class);

        List<ServiceInstance> instances = discoveryClient.getInstances("provider");
        ServiceInstance info = instances.get(0);
        String host = info.getHost();
        int port = info.getPort();
        String url = String.format("http://%s:%s/user", host, port);
        return restTemplate.getForObject(url, List.class);
    }

}

2.5 Eureka详解

3. 负载均衡 Spring Cloud Ribbon

3.1 启动2个提供者

port=8080和port=8081

3.2 开启消费者负载均衡

@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate restTemplate() {
    return new RestTemplate();
}

3.3 通过服务名称调用

    @GetMapping
    private List<User> findAll() {
//        String url = "http://localhost:8081/user";

//        List<ServiceInstance> instances = discoveryClient.getInstances("provider");
//        ServiceInstance info = instances.get(0);
//        String host = info.getHost();
//        int port = info.getPort();
//        String url = String.format("http://%s:%s/user", host, port);

        // 通过服务名称调用
        String url = String.format("http://provider/user");
        return restTemplate.getForObject(url, List.class);
    }

3.4 配置负载策略

# 修改服务地址轮询策略,默认是轮询,配置之后变随机
# RandomRule 随机
# RoundRobinRule 轮询策略
provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

4. 熔断器 Spring Cloud Hystrix

4.1 什么是熔断器

Hystrix,英文意思是豪猪,全身是刺,刺是一种保护机制。Hystrix也是Netflix公司的一款组件。

Hystrix的作用是什么?

Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应。

4.2 雪崩效应

  • 微服务中,一个请求可能需要多个微服务接口才能实现,会形成复杂的调用链路。
  • 如果某服务出现异常,请求阻塞,用户得不到响应,容器中线程不会释放,于是越来越多用户请求堆积,越来越多线程阻塞。
  • 单服务器支持线程和并发数有限,请求如果一直阻塞,会导致服务器资源耗尽,从而导致所有其他服务都不可用,从而形成雪崩效应;

Hystrix解决雪崩问题的手段,主要是服务降级**(兜底)**,线程隔离;

4.3 熔断器简单实现

在springcloud-consumer中添加依赖

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

配置熔断器注解

// @SpringCloudApplication =等同于@SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker
//@EnableCircuitBreaker // 开启熔断
//@EnableDiscoveryClient // 注册到注册中心
//@SpringBootApplication
@SpringCloudApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

    @Bean
    @LoadBalanced // 开启负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

编写服务降级处理方法:使用@HystrixCommand定义fallback方法。

@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "findByIdFallback")
public User findById(@PathVariable Long id) {
    if (id == 1) {
        throw new RuntimeException("too busy!!!");
    }
    // 通过服务名称调用
    String url = String.format("http://provider/user/%d", id);
    return restTemplate.getForObject(url, User.class);
}

// 返回值和 findById 方法需要相同
public User findByIdFallback(Long id) {
    return new User();
}

测试请求:localhost:8082/consumer/1 抛出异常后熔断器生效

4.4 熔断器的配置策略

# 配置熔断策略:
hystrix:
  command:
    default:
      circuitBreaker:
        # 原理分析中解释配置含义
        # 强制打开熔断器 默认false关闭的。测试配置是否生效
        forceOpen: false
        # 触发熔断错误比例阈值,默认值50%
        errorThresholdPercentage: 50
        # 熔断后休眠时长,默认值5秒
        sleepWindowInMilliseconds: 5000
        # 熔断触发最小请求次数,默认值是20
        requestVolumeThreshold: 10
      execution:
        isolation:
          thread:
            # 熔断超时设置,默认为1秒
            timeoutInMilliseconds: 2000

修改springcloud-provider中UserController的findById方法

@GetMapping("{id}")
public User findById(@PathVariable Long id) {
    try {
        Thread.sleep(3000); // 熔断器配置 2 秒
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return userService.getById(id);
}

测试:localhost:8082/consumer/2 实际请求 3 秒 熔断器生效

4.5 熔断器的原理

熔断器状态机有3个状态:

  • 关闭状态,所有请求正常访问
  • 打开状态,所有请求都会被降级。
    • Hystrix会对请求情况计数,当一定时间失败请求百分比达到阈值,则触发熔断,断路器完全关闭
    • 默认失败比例的阈值是50%,请求次数最低不少于20次
  • 半开状态
    • 打开状态不是永久的,打开一会后会进入休眠时间(默认5秒)。休眠时间过后会进入半开状态。
    • 半开状态:熔断器会判断下一次请求的返回状况,如果成功,熔断器切回关闭状态。如果失败,熔断器切回打开状态。

熔断器的核心解决方案:线程隔离和服务降级。

  • 线程隔离。
  • 服务降级(兜底方法)。

线程隔离和服务降级之后,用户请求故障时,线程不会被阻塞,更不会无休止等待或者看到系统奔溃,至少可以看到执行结果(熔断机制)。

什么时候熔断

  1. 访问超时
  2. 服务不可用(死了)
  3. 服务抛出异常(虽然有异常但还活着)
  4. 其他请求导致服务异常到达阈值,所有服务都会被降级

4.6 配置全局熔断器

在控制器添加注解 @DefaultProperties(defaultFallback = “defaultFallback”)

在目标方法上添加注解 @HystrixCommand //不指定 fallbackMethod 即可

5. 远程调用 Spring Cloud Feign

前面学习中,使用RestTemplate大大简化了远程调用的代码

String url = String.format("http://provider/user/%d", id);
return restTemplate.getForObject(url, User.class);

而我们只用spring cloud 的Feign 功能可以更加优雅的来实现。

5.1 Feign的简介

Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,是以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

5.1 入门案例

5.2.1 添加依赖

在springcloud-consumer中添加依赖

<!--配置feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

5.2.2 编写Feign客户端

/**
 * 作者: jack
 * 时间: 2020-07-07 19:15
 * 描述: UserClient
 */
@FeignClient("provider")
public interface UserClient {

    @GetMapping("/user/{id}") // 这里的url要写完整的
    public User findById(@PathVariable Long id);

}

5.2.3 使用Feign客户端

开启Feign功能

@SpringCloudApplication
@EnableFeignClients
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
    }

    @Bean
    @LoadBalanced // 开启负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

在ConsumerController中改造

@RequestMapping("/consumer")
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    // 注入Feign客户端
    @Autowired
    private UserClient userClient;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping
    private List<User> findAll() {
        String url = String.format("http://provider/user");
        return restTemplate.getForObject(url, List.class);
    }


    @GetMapping("{id}")
    @HystrixCommand(fallbackMethod = "findByIdFallback")
    public User findById(@PathVariable Long id) {
        // 通过服务名称调用
        // String url = String.format("http://provider/user/%d", id);
        // return restTemplate.getForObject(url, User.class);

        // 使用Feign客户端的方式调用
        return userClient.findById(id);
    }

    public User findByIdFallback(Long id) {
        return new User();
    }

}

修改提供者的方法

    @GetMapping("{id}")
    public User findById(@PathVariable Long id) {
//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        return userService.getById(id);
    }

测试请求 http://localhost:8082/consumer/1

5.2 Feign客户端支持负载均衡

Feign中已经自动集成Ribbon负载均衡,因此不需要自定义RestTemplate进行负载均衡的配置

5.3 Feign客户端熔断器使用

5.3.1 在application.yml中开启feign熔断器支持

# feign熔断器支持开启
feign:
  hystrix:
    enabled: true

5.3.2 编写FallBack处理类,实现FeignClient客户端

@Component
public class UserClientFallback implements UserClient {
    @Override
    public User findById(Long id) {
        User user = new User();
        user.setName("用户不存在");
        return user;
    }
}

5.3.3 在@FeignClient注解中,指定FallBack处理类

PS:这里要关闭之前的熔断器

@FeignClient(value = "provider", fallback = UserClientFallback.class)
public interface UserClient {

    @GetMapping("/user/{id}") // 这里的url要写完整的
    public User findById(@PathVariable Long id);

}

修改UserController用来测试

@GetMapping("{id}")
public User findById(@PathVariable Long id) {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return userService.getById(id);
}

测试:http://localhost:8082/consumer/1

5.4 请求压缩和响应压缩

开启以下配置即可

feign:
  hystrix:
    enabled: true
  compression:
    request:
      enabled: true
      # 压缩的文件类型
      mime-types: text/html,application/xml,application/json
      # 压缩文件的其实大小
      min-request-size: 1024
    response:
      enabled: true

6. 网关 Spring Cloud Gateway

Spring Cloud Gateway 是Spring Cloud团队的一个全新项目,基于Spring 5.0、SpringBoot2.0、Project Reactor 等技术开发的网关。 旨在为微服务架构提供一种简单有效统一的REST 请求路由管理方式。

Spring Cloud Gateway 作为SpringCloud生态系统中的网关,目标是替代Netflflix Zuul。Gateway不仅提供统一路由方式,并且基于Filter链的方式提供网关的基本功能。例如:安全,监控/指标,和限流。

本身也是一个微服务,需要注册到Eureka

**网关的核心功能:**过滤(权限)、路由

核心概念:

  1. 路由(route)
  2. 断言Predicate函数:路由转发规则
  3. 过滤器(Filter)

spring cloud Gateway 不支持spring boot web包 所以这边要把父工程的 spring boot web删除在需要的子工程添加,前面忘记了就懒得修改笔记了。注意以下

6.1 入门案例

创建子模块springcloud-gateway并添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

编写启动类并注册为eureka客户端

/**
 * 作者: jack
 * 时间: 2020-07-07 20:02
 * 描述: GatewayApplication
 */
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

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

配置application.yml

server:
  port: 8083
spring:
  application:
    name: gateway
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # 匹配所有请求
            allowedOrigins: "*" #跨域处理 允许所有的域
            allowedMethods: # 支持的方法
              - GET
              - POST
              - PUT
              - DELETE
      routes:
        - id: provider-router # 唯一标识
          uri: lb://provider # 路由地址,动态路由
          predicates: # 断言
            - Path=/user/** # 请求url 多个使用逗号
eureka:
  client:
    service-url:
      defauleZone: http://127.0.0.1:8761/eureka

启动网关测试:http://localhost:8083/user/1 可以通过网关的端口进行访问,说明网关配置成功

6.2 路由前缀

在gateway中可以通过配置路由的过滤器PrefifixPath 实现映射路径中的前缀添加。可以起到隐藏接口地址的作用,避免接口地址暴露。

predicates:
  - Path=/**
filters:
  - PrefixPath=/user

测试访问地址:http://localhost:8083/1

在gateway中通过配置路由过滤器StripPrefifix,实现映射路径中地址的去除。通过StripPrefifix=1来指定路由要去掉的前缀个数。如:路径/api/user/1将会被路由到/user/1。

predicates:
  - Path=/api/**
filters:
  - StripPrefix=1

测试访问地址:http://localhost:8083/api/user/1

6.4 过滤器

过滤器作为网关的其中一个重要功能,就是实现请求的鉴权。前面的 路由前缀 章节中的功能也是使用过滤器实现的。

Gateway自带过滤器有几十个,常见自带过滤器有:

过滤器名称说明
AddRequestHeader对匹配上的请求加上Header
AddRequestParameters对匹配上的请求路由
AddResponseHeader对从网关返回的响应添加Header
StripPrefifix对匹配上的请求路径去除前缀
PrefifixPath对匹配上的请求路径添加前缀

官方文档

配置全局过滤器

spring:
  application:
    name: gateway
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=ilove,web

请求后可以看到响应头添加了 ilove=web

6.4.1自定义全局过滤器

模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行

@Component
public class TokenFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("TokenFilter is filter");
        // TO DO
        return chain.filter(exchange);
    }

    //设置过滤器执行顺序,值越小,优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}

6.4.2 自定义局部过滤器

自定义GatewayFilter有两种实现方式,一种是直接实现GatewayFilter接口,另一种是继承AbstractGatewayFilterFactory类 ,任意选一种即可

package com.iweb.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 作者: jack
 * 时间: 2020-07-07 21:24
 * 描述: AuthorizeGatewayFilter
 * Authorize(自定义) GatewayFilterFactory(固定写法)
 */
@Component
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config> {

    /**
     * Prefix key.
     */
    public static final String AUTHOR_NAME = "name"; // 接收配置的参数 这里可以不写

    public AuthorizeGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(AUTHOR_NAME);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            System.out.println("AuthorizeGatewayFilterFactory is filter");
            System.out.println(config.name);
            return chain.filter(exchange);
        };
    }

    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

在application.yml中配置

spring:
  application:
    name: gateway
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=ilove,web
      globalcors:
        cors-configurations:
          '[/**]': # 匹配所有请求
            allowedOrigins: "*" #跨域处理 允许所有的域
            allowedMethods: # 支持的方法
              - GET
              - POST
              - PUT
              - DELETE
      routes:
        - id: provider-router # 唯一标识
          uri: lb://provider # 路由地址,动态路由
          predicates:
            - Path=/api/**
          filters:
            - StripPrefix=1
            - Authorize=iweb

控制台输出

AuthorizeGatewayFilterFactory is filter
iweb
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud是一个用于构建分布式系统的开发工具集合。它提供了一些常用的组件和框架,包括服务注册和发现、负载均衡、断路器、分布式配置等等。在使用Spring Cloud时,有一些常见的错误和注意事项需要注意。 首先,关于Spring Boot和Spring Cloud版本对应错误。在使用Spring Cloud时,需要确保Spring Boot和Spring Cloud的版本兼容。不同版本之间可能存在依赖冲突或不兼容的情况,因此需要根据官方文档或者相关文档来选择合适的版本。 另外,Spring Cloud Config是一个用于集中管理和动态获取配置的工具。它支持从Git、SVN或本地文件系统中获取配置文件,并提供了服务器和客户端支持。你可以通过官方使用说明文档了解更多关于Spring Cloud Config的详细信息。 此外,关于选择使用Nacos还是Eureka作为服务注册和发现组件的问题。Nacos是一个功能更强大的服务注册和发现组件,它整合了Spring Cloud Eureka、Spring Cloud Config和Spring Cloud Bus的功能。使用Nacos可以实现配置的中心动态刷新,而不需要为配置中心新增集群或使用消息队列。另一方面,Eureka是Spring Cloud原生全家桶的一部分,相对来说更加稳定一些。选择使用哪个组件需要根据具体的需求和项目特点来决定。 综上所述,Spring Cloud是一个用于构建分布式系统的开发工具集合,它提供了一些常用的组件和框架。在使用Spring Cloud时,需要注意Spring Boot和Spring Cloud版本的兼容性,并可以使用Spring Cloud Config来动态获取配置。同时,可以选择使用Nacos或Eureka作为服务注册和发现组件,具体选择需要根据项目需求来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值