SpringCloud-Alibaba学习(五):OpenFeign远程调用

1、介绍

SpringCloud OpenFeign 是 SpringCloud 的子项目之一,不属于第三方公司,是一种声明式、模板化的 HTTP 客户端。在 SpringCloud 中使用 OpenFeign 时,可以做到像调用本地方法一样发起远程调用,优化了编码体验。同时 OpenFeign 通过集成 Ribbon 实现了客户端的负载均衡。

  • Nacos-server:注册中心,解决服务注册与发现
  • Ribbon:客户端负载均衡器,解决服务集群负载均衡调用问题
  • OpenFeign:声明式 HTTP 客户端,代替 RestTemplate 实现远程调用。

2、使用示例

2.1 示例说明

服务:

  • cloud-openfeign-points 积分服务为服务提供者
  • cloud-openfeign-order 订单服务为服务消费者

2.2 服务搭建

2.2.1 cloud-openfeign-points 服务

参考:https://www.cnblogs.com/liuyiyuan/p/16421731.html#32-搭建工程

改改配置文件的这几个配置项:

# 服务端口
server.port=9004
server.servlet.context-path=/openfeign-points
# 服务名称 必须有 保证唯一性
spring.application.name=openfeign-points

crud 接口

@RestController
@RequestMapping("/points")
public class PointsController {

    List<Points> db = new ArrayList<>();

    @PostMapping("/save")
    public HttpResponse<Void> save(@RequestBody Points points) {
        System.out.println("添加积分 "+points);
        db.add(points);
        return HttpResponse.success();
    }

    @PutMapping("/update")
    public HttpResponse<Void> update(@RequestBody Points points)  {
        System.out.println("更新积分 " + points);
        db.stream()
                .filter(e -> e.getPointsId().equals(points.getPointsId()))
                .peek(e -> {
                    e.setType(points.getType());
                    e.setCount(points.getCount());
                });

        return HttpResponse.success();
    }

    @DeleteMapping("/delete")
    public HttpResponse<Void> deleteById(Integer pointsId) {
        System.out.println("删除id=" + pointsId);

        db.removeIf(e -> e.getPointsId().equals(pointsId));
        return HttpResponse.success();
    }


    @GetMapping("/{pointsId}")
    public HttpResponse<Points> findById(@PathVariable("pointsId") Integer pointsId) {
        Optional<Points> optional = db.stream().filter(e -> e.getPointsId().equals(pointsId)).findFirst();
        return HttpResponse.success(optional.orElse(null));
    }

    @GetMapping("/search")
    public HttpResponse<Points> search(Integer pointsId, String type) {

        System.out.println("搜索条件:" + pointsId + " " + type);

        Optional<Points> optional = db.stream()
                .filter(e -> e.getPointsId().equals(pointsId) && e.getType().equals(type))
                .findFirst();
        return HttpResponse.success(optional.orElse(null));
    }

    @PostMapping("/searchByEntity")
    public HttpResponse<List<Points>> searchByEntity(@RequestBody Points points) {
        System.out.println("搜索条件 entity:" + points);
        return HttpResponse.success(db);
    }

}


2.2.2 cloud-openfeign-order 服务

服务消费方使用 OpenFeign 方式进行远程调用,不再注入 RestTemplate 对象

增加 OpenFeign 的依赖:

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

OpenFeign 内部也已经引入了 Ribbon 不需要额外依赖

启动类添加注解 @EnableFeignClients 启用 OpenFeign

2.2.3 接口声明

创建一个单独的 api 模块 cloud-openfeign-api,用于暴露服务提供者的接口,同时使用 OpenFeign 的注解标注接口

api 模块由服务提供方定义,作为公共包发布出去,可以供多个消费方使用。

依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>cc.yuanspace</groupId>
            <artifactId>cloud-openfeign-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
/**
 * 积分接口声明
 */
// value 指定服务名   path指定路径前缀,如果服务有上下文路径时使用
@FeignClient(value = "openfeign-points", path = "/openfeign-points")
@RequestMapping("/points")
public interface PointsApi {

    // 方法结构与服务接口一致,只是没有方法体
    @PostMapping("/save")
    HttpResponse<Void> save(@RequestBody Points points);

    @PutMapping("/update")
    HttpResponse<Void> update(@RequestBody Points points);


    /**
     * 使用url参数时,@RequestParam不可以省略,必须有,用于定义参数的key
     * @param pointsId
     * @return
     */
    @DeleteMapping("/delete")
    HttpResponse<Void> deleteById(@RequestParam("pointsId") Integer pointsId);


    @GetMapping("/{pointsId}")
    HttpResponse<Points> findById(@PathVariable("pointsId") Integer pointsId);

    @GetMapping("/search")
    HttpResponse<Points> search(@RequestParam("pointsId") Integer pointsId, @RequestParam("type") String type);

    @PostMapping("/searchByEntity")
    HttpResponse<List<Points>> searchByEntity(@RequestBody Points points);
}

2.2.4 接口调用

服务消费方的启动类上注解添加扫描路径,扫描 @FeignClient 注解的类

可以使用 @AutoWired 注入接口的代理实现

@RestController
public class OrderController {
    
    @Autowired
    private PointsApi pointsApi;
    
    @RequestMapping("/test")
    public HttpResponse<Void> test() {
        Points points = new Points(1, 10, "2");
        HttpResponse<Void> response = pointsApi.save(points);
        return response;
    }
}

3、常用配置

# openfeign 的常用配置
# false表示当第一次发请求时才去注册中心拉取服务列表   true表示项目启动立即拉取
ribbon.eager-load.enabled=true
# 指定哪些服务立即拉取服务列表
ribbon.eager-load.clients=openfeign-points
# 设置指定服务的连接超时时间,单位 ms
feign.client.config.openfeign-points.connect-timeout=1000
# 设置指定服务的响应超时时间,单位 ms
feign.client.config.openfeign-points.read-timeout=1000
# 设置默认超时时间,单位 ms
feign.client.config.default.connect-timeout=1000
feign.client.config.default.read-timeout=1000
posted @ 2022-07-02 08:39  originyuan  阅读(395)  评论(0编辑  收藏  举报