Spring-Cloud-Alibaba 学习笔记

SpringCloudAlibaba学习笔记

  • 简介

官方网站:Spring Cloud Alibaba

官方文档:Document

版本说明:版本说明

github:Spring Cloud Alibaba github

  • 学习环境

环境:

jdk:1.8

maven:3.6.3

spring-boot:2.5.2

spring-cloud:2020.0.3

spring-cloud-alibaba:2021.1

1.搭建父工程及相关服务

搭建父工程

  • 新建maven项目

  • 配置父工程pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hikw</groupId>
    <artifactId>Spring-Cloud-Alibaba-Parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>provider</module>
        <module>consumer</module>
    </modules>
    <name>spring-cloud-alibaba</name>
    <description>This is the parent project of spring cloudalibaba</description>

    <!--打包格式配置-->
    <packaging>pom</packaging>

    <!--版本控制-->
    <properties>
        <spring-boot.version>2.5.2</spring-boot.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>

    <!--通用依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--全局依赖管理-->
    <dependencyManagement>
        <dependencies>
            <!--spring-boot依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring-cloud依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring-cloud-alibaba依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--打包工具配置-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!--配置阿里云镜像-->
    <repositories>
        <repository>
            <id>spring</id>
            <url>https://maven.aliyun.com/repository/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

搭建相关服务

  • provider服务
  • 配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
       <artifactId>Spring-Cloud-Alibaba-Parent</artifactId>
       <groupId>com.hikw</groupId>
       <version>1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>

   <artifactId>provider</artifactId>
   <version>1.0-SNAPSHOT</version>
   <groupId>com.hikw</groupId>
   <description>This is a service provider</description>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
   </dependencies>
</project>
  • 配置application.yml
# 配置端口号
server:
 port: 8888
spring:
 # 配置服务名
 application:
   name: providers
  • 配置ProviderController
@RestController
@Slf4j
public class ProviderController {

   @Value("${server.port}")
   private String port;

   //获取服务端口
   @GetMapping("/provider/getPort")
   public String StringgetPort() {
       log.info("当前端口号:{}", port);
       return port;
   }
}
  • 添加入口类
@SpringBootApplication
public class ProviderApplication {

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

}
  • consumer服务
  • 配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
       <artifactId>Spring-Cloud-Alibaba-Parent</artifactId>
       <groupId>com.hikw</groupId>
       <version>1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>

   <artifactId>consumer</artifactId>
   <version>1.0-SNAPSHOT</version>
   <groupId>com.hikw</groupId>
   <description>This is a service consumer</description>

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

</project>
  • 配置application.yml
# 配置端口号
server:
 port: 9999
spring:
 # 配置服务名
 application:
   name: consumers
  • 添加入口类
@SpringBootApplication
public class ConsumerApplication {

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

}

2.服务注册与发现

2.1 nacos使用

官方文档:Nacos

Nacos下载:Dowload

如何使用:

1.下载nacos后解压缩

2.找到解压缩后目录中的bin目录下的startup.cmd运行

由于nacos默认是以集群模式启动,所以第一次会无法启动。需要修改startup.cmd文件中的MOD属性为standalone

rem 单机模式启动
set MODE="standalone"

rem 集群模式启动(默认)
set MODE="cluster"

3.访问http://127.0.0.1:8848/nacos/进入首页

4.首次进入需要登录(登录账号和密码均为nacos)

在这里插入图片描述

2.2 服务注册

这里以provider服务为例

  • 添加nacos依赖

由于SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer,所以不引入spring-cloud-loadbalancer会报错加入spring-cloud-loadbalancer依赖 并且在nacos中排除ribbon依赖,不然loadbalancer无效

<!--引入nacos依赖并排除ribbon-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--引入loadbalancer依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
  • application.yml添加配置
# 配置端口号
server:
  port: 8888
spring:
  # 配置服务名
  application:
    name: providers
  cloud:
    nacos:
      # 指定nacos地址
      server-addr: 127.0.0.1:8848
      # 指定注册中心地址
      discovery:
        server-addr: ${spring.cloud.nacos.server-addr}
  • 启动provider服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q4yPt8vP-1629799312099)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726143858047.png)]

2.3 服务发现

这里以consumer服务为例

  • 添加nacos依赖

由于SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer,所以不引入spring-cloud-loadbalancer会报错加入spring-cloud-loadbalancer依赖 并且在nacos中排除ribbon依赖,不然loadbalancer无效

<!--引入nacos依赖并排除ribbon-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--引入loadbalancer依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>v
  • 添加ConsumerController
@RestController
public class ConsumerController {

    @Autowired
    private DiscoveryClient discoveryClient;

    //获取providers服务的服务列表
    @GetMapping("/consumer/getServiceInstance")
    public List<ServiceInstance> geterviceInstance() {
        return this.discoveryClient.getInstances("providers");
    }

}
  • 访问http://127.0.0.1:9999/consumer/getServiceInstance即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goTtnJdJ-1629799312103)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726144711124.png)]

3.服务通信

  • 启动三个provider服务
    在这里插入图片描述
    在这里插入图片描述

3.1 基本服务调用(不推荐)

  • 编辑ConsumerController(重点)
@RestController
@Slf4j
public class ConsumerController {

    @Autowired
    //RestTemplate不能自动装载  需要手动配置Bean
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    
    //获取providers服务的服务列表
    @GetMapping("/consumer/getServiceInstance")
    public List<ServiceInstance> geterviceInstance() {
        return this.discoveryClient.getInstances("providers");
    }

    
    /*
    服务调用
    方法1:通过RestTemplate直接调用(不常用)
    缺点:1.uri固定写死  2.不能实现负载均衡  3.后期维护困难
     */
//    @GetMapping("/consumer/serviceInvoking")
//    public String serviceInvoking() {
//        String result = restTemplate.getForObject("http://127.0.0.1:8888/provider/getPort", String.class);
//        log.info("调用成功,端口为:{}", result);
//        return "调用成功,端口为:" + result;
//    }

    
    /*
    服务调用
    方法2:通过DiscoveryClient+RestTemplate调用(不常用)
    缺点:1.代码冗余量大  2.后期维护困难
    */
//    @GetMapping("/consumer/serviceInvoking")
//    public String serviceInvoking() {
//        //获取服务列表
//        List<ServiceInstance> serviceInstanceList = this.discoveryClient.getInstances("providers");
//        //手动实现负载均衡
//        int num = ThreadLocalRandom.current().nextInt(serviceInstanceList.size());
//        //获取实例
//        ServiceInstance serviceInstance = serviceInstanceList.get(num);
//        //通过RestTemplate调用
//        String result = restTemplate.getForObject(serviceInstance.getUri() + "/provider/getPort", String.class);
//        log.info("调用成功,端口为:{}", result);
//        return "调用成功,端口为:" + result;
//    }

    
    /*
    服务调用
    方法3:通过Ribbon+RestTemplate调用(不常用)
    使用:在RestTemplate Bean上添加@LoadBalanced注解实现自动负载均衡
    缺点:1.后期维护困难
    */
    @GetMapping("/consumer/serviceInvoking")
    public String serviceInvoking() {
        // http://服务ID/服务地址
        String result = restTemplate.getForObject("http://providers/provider/getPort", String.class);
        log.info("调用成功,端口为:{}", result);
        return "调用成功,端口为:" + result;
    }


}
  • 配置RestTemplate Bean
@Configuration
public class CommonConfiguration {

    @Bean
    @LoadBalanced//方法3调用时需要加此注解
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

}

3.2 OpenFeign调用(推荐)

  • 引入openfeign依赖
<!--引入openfeign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 入口类添加@EnableFeignClients注解开启Feifn支持
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {

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

}
  • 开发Feign客户端接口 ProviderClient
@FeignClient("providers")
public interface ProviderClient {

    @GetMapping("/provider/getPort")
    String getPort();

}
  • 实现调用
@RestController
@Slf4j
public class ConsumerController {

    @Autowired
    private ProviderClient providerClient;

    
    @GetMapping("/consumer/serviceInvoking")
    public String serviceInvoking() {
        String result = providerClient.getPort();
        log.info("调用成功,端口为:{}", result);
        return "调用成功,端口为:" + result;
    }


}

扩展:openfeign常用配置

# 配置随机负载均衡策略
providers:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# 配置日志输出
feign:
  client:
    config:
      providers:
        loggerLevel: FULL
          connectTimeout: 5000
          readTimeout: 5000
logging:
  level:
    com.hikw.clients.ProviderClient: debug
# 启用OkHttp
feign:
  okhttp:
    enabled: true

4.服务限流降级

Sentinel:Sentinel官网

4.1 Sentinel 使用

  • 通过 Dowload 下载好Sentinel,使用下列命令执行jar包
java -jar sentinel-dashboard-1.8.2.jar
  • 通过127.0.0.1:8080访问Sentinel首页(默认密码账户为:sentinel )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kLc8J71v-1629799312109)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726164428842.png)]

以下步骤全在provider服务中进行

  • 添加sentinel依赖以及actuator依赖
<!--引入sentinel依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--引入actuator依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • application.yml添加配置
# 指定sentinel地址
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
# 暴露所有端口(用于监控)
management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 访问http://127.0.0.1:9999/consumer/serviceInvoking即可发现访问已被监控
    在这里插入图片描述
    在这里插入图片描述

4.2 流量控制

  • 选择需要添加流控的地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VchU5ja1-1629799312112)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726165959161.png)]

  • 操作详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXFqHeoK-1629799312113)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726170101095.png)]

资源名:即访问资源路径(设置资源)

针对来源:一般默认

阈值类型:OPS(常用)/并发线程数

单机阈值:即一秒钟可以允许的请求数

是否集群:集群设置

流控模式:

  • 直接:对设置资源进行限流
  • 关联:若对关联资源进行限流,关联资源会影响到设置资源(即当关联资源被限流时,设置资源也会被影响不可访问)
  • 链路:对service层进行限流

流控效果:

  • 快速失败:访问失败时直接返回异常信息
  • Warm Up:预加载(预热时间)
  • 排队等待:第一次调用超出阈值时则会在规定的时间内再次进行调用,如果第二次也失败则抛出异常

4.3 熔断(降级)控制

  • 选择需要熔断的地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w0vfAn39-1629799312114)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726171930320.png)]

  • 操作详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHocD4ya-1629799312115)(C:\Users\hy\AppData\Roaming\Typora\typora-user-images\image-20210726172015317.png)]

资源名:即访问资源路径(设置资源)

熔断策略:

  • 慢调用比例
  • 异常比例
  • 异常数

最大RT:单个请求的响应时间

比利阈值:比例之间阈值

熔断时长:熔断时间长度

最小请求数:1秒内5次请求机会(判断是否有问题)

统计时长:统计时间

4.4 热点控制

在这里插入图片描述

对某个参数进行限流

4.5 授权控制

  • 添加配置类
public class RequestOriginParserConfiguration implements RequestOriginParser {

    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        String name = httpServletRequest.getParameter("name");
        if (StringUtils.isEmpty(name)) {
            throw new RuntimeException("未授权!");
        }
        return name;
    }
}
@Configuration
public class SentinelConfiguration {

    @PostConstruct
    public void init() {
        WebCallbackManager.setRequestOriginParser(new RequestOriginParserConfiguration());
    }

}

5.消息队列

官网:Apache RocketMQ

下载:Download

这里使用windows启动RocketMQ

1.配置环境变量

变量名:ROCKETMQ_HOME

变量值:你的RocketMQ解压缩后的路径

2.cmd到RocketMQ的bin目录下

  • 启动NameServer服务
start mqnamesrv.cmd
  • 启动Broker服务

首先修改内存大小:

修改runserver.cmdrunbroker.cmd 的下类命令:

set "JAVA_OPT=%JAVA_OPT% -server -Xms256m -Xmx256m -Xmn128m"

在启动服务

start mqbroker.cmd -n 127.0.0.1:9876
  • 引入RocketMQ相关依赖(provider&consumer)
<!--引入RocketMQ依赖-->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.9.0</version>
</dependency>

6.服务网关

6.1 gateway使用

  • 新建网关服务gateway(注意不能有web组件依赖)

  • 手动配置(方式一)

引入 gateway 依赖

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

配置 application.yml

# 设置端口号
server:
  port: 80
spring:
  # 配置服务名
  application:
    name: gateway
  cloud:
    gateway:
      # 开启根据服务名动态获取路由功能
      discovery:
        locator:
          enabled: true
      # 配置网关路由
      routes:
        - id: provider_route
          # 单体配置
#          uri: http://127.0.0.1:8888
          # 集群配置
          uri: lb://providers
          predicates:
            - Path=/provider/**

        - id: consumer_route
#          uri: http://127.0.0.1:9999
          uri: lb://consumers
          predicates:
            - Path=/consumer/**

通过 127.0.0.1/provider/getPort 即可访问

  • 自动配置(方式二)

添加nacos依赖

<!--引入nacos依赖并排除ribbon-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

配置 application.yml

# 设置端口号
server:
  port: 80
spring:
  # 配置服务名
  application:
    name: gateway
  cloud:
    gateway:
      # 开启根据服务名动态获取路由功能
      discovery:
        locator:
          enabled: true

此时通过nacos注册后使用 127.0.0.1/providers/provider/getPort 也可以访问(127.0.0.1/服务名/服务URL)

6.2 路由限流

  • 删除 nacos 依赖并引入 sentinel适配器依赖
<!--引入sentinel网关限流依赖-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
  • 编写配置类 GatewayConfiguration
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    //配置限流异常处理
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler((viewResolvers), serverCodecConfigurer);
    }

    //配置初始化限流参数
    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(
                new GatewayFlowRule("provider_route")
                        .setCount(1)
                        .setIntervalSec(1)
        );
        GatewayRuleManager.loadRules(rules);
    }

    //初始化限流过滤器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    //自定义限流异常页面
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map map = new HashMap();
                map.put("code", 0);
                map.put("msg", "被限流了");
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromObject(map));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

}

Sec(1)
);
GatewayRuleManager.loadRules(rules);
}

//初始化限流过滤器
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
    return new SentinelGatewayFilter();
}

//自定义限流异常页面
@PostConstruct
public void initBlockHandlers() {
    BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
        @Override
        public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
            Map map = new HashMap();
            map.put("code", 0);
            map.put("msg", "被限流了");
            return ServerResponse.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromObject(map));
        }
    };
    GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_何同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值