双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持

Spring Cloud Alibaba Sentinel 支持对 RestTemplate 调用的服务进行服务保护。需要在构造 RestTemplate Bean 时添加 @SentinelRestTemplate 注解。

一、启动类

OrderServiceRestApplication.java

package com.example;

import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import com.example.exception.ExceptionUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class OrderServiceRestApplication {

    @Bean
    @LoadBalanced
    @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class,
            fallback = "fallback", fallbackClass = ExceptionUtil.class)
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

二、服务熔断处理类

ExceptionUtil.java 必须使用静态方法。

package com.example.exception;

import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.example.pojo.Product;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;

public class ExceptionUtil {

    // 服务流量控制处理
    public static ClientHttpResponse handleException(HttpRequest request,
                                                     byte[] body,
                                                     ClientHttpRequestExecution execution,
                                                     BlockException exception) {
        exception.printStackTrace();
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new Product(1, "服务流量控制处理-托底数据", 1, 2666D)));
    }

    // 服务熔断降级处理
    public static ClientHttpResponse fallback(HttpRequest request,
                                                    byte[] body,
                                                    ClientHttpRequestExecution execution,
                                                    BlockException exception) {
        exception.printStackTrace();
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new Product(1, "服务熔断降级处理-托底数据", 1, 2666D)));
    }

}

三、访问

控制台设置流量控制规则,定义资源访问的 QPS 为 1(每秒能处理查询数目)。

快速刷新页面多次访问:http://localhost:9090/order/1 结果如下:
双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持_第1张图片

四、OpenFeign 支持

添加依赖

<!-- spring cloud alibaba sentinel 依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- spring cloud openfeign 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

开启 Sentinel

server:
  port: 9091 # 端口

spring:
  application:
    name: order-service-feign # 应用名称
  cloud:
    # 配置 Nacos 注册中心
    nacos:
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现,设置为 false 即可
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
    # 配置 Sentinel
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080

# feign 开启 sentinel 支持
feign:
  sentinel:
    enabled: true

熔断降级

ProductServiceFallback.java

package com.example.fallback;

import com.example.pojo.Product;
import com.example.service.ProductService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 服务熔断降级处理可以捕获异常
 */
@Slf4j
@Component
public class ProductServiceFallbackFactory implements FallbackFactory<ProductService> {

    @Override
    public ProductService create(Throwable throwable) {
        return new ProductService() {
            @Override
            public Product selectProductById(Integer id) {
                // 获取日志,在需要捕获异常的方法中进行处理
                log.error("product-service 服务的 selectProductById 方法出现异常,异常信息如下:"
                        + throwable);
                return new Product(id, "托底数据", 1, 2666D);
            }
        };
    }

}

消费服务

ProductService.java

package com.example.service;

import com.example.fallback.ProductServiceFallbackFactory;
import com.example.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// 声明需要调用的服务
@FeignClient(value = "product-service", fallbackFactory = ProductServiceFallbackFactory.class)
public interface ProductService {

    /**
     * 根据主键查询商品
     *
     * @param id
     * @return
     */
    @GetMapping("/product/{id}")
    Product selectProductById(@PathVariable("id") Integer id);

}

OrderServiceImpl.java

package com.example.service.impl;

import com.example.pojo.Order;
import com.example.service.OrderService;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private ProductService productService;

    /**
     * 根据主键查询订单
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-001", "中国", 2666D,
                Arrays.asList(productService.selectProductById(1)));
    }

}

控制层

package com.example.controller;

import com.example.pojo.Order;
import com.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @Autowired
    private OrderService orderService;

    /**
     * 根据主键查询订单
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }

}

启动类

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

// 开启 FeignClients 注解
@EnableFeignClients
// 开启 @EnableDiscoveryClient 注解,当前版本默认会开启该注解
//@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceFeignApplication {

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

}

测试

控制台信息如下:

双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持_第2张图片

添加流量控制规则,定义资源访问的 QPS 为 1(每秒能处理查询数目)。

双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持_第3张图片

快速刷新页面多次访问:http://localhost:9091/order/1 结果如下:

双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持_第4张图片

或者关闭服务提供者,访问:http://localhost:9091/order/1 结果如下:

双剑合璧Nacos结合Sentinel实现流量安全控制(三):RestTemplate 支持和OpenFeign 支持_第5张图片
作者:哈喽沃德先生,谢谢关注哈喽沃德先生公众号,点击 获取spring微服务架构spring全家桶视频课程。

你可能感兴趣的:(java,spring,spring,boot,java)