Skip to main content

远程调用

RestTemplate

Spring提供了RestTemplate工具,可以方便的实现HTTP请求的发送。

  1. 注入RestTemplateSpring容器

  2. 通过构造函数注入到Service

    @RequiredArgsConstructor:创建包含必须初始化(final)的属性的构造函数

  3. 发起远程调用

    public <T> ResponseEntity</T> exchange(
    String url, // 请求路径
    HttpMethod method, // 请求方式
    @Nullable HttpEntity<?> requestEntity, // 请求实体,可以为空
    Class<T> responseType, // 返回值类型
    Map<String, ?> uriVariables // 请求参数,jdk11的写法
    )
    // jdk8的Map写法
    String joinedIds = CollUtil.join(itemIds, ",");

    // 创建一个临时的可变 Map
    Map<String, String> tempMap = new HashMap<>();
    tempMap.put("ids", joinedIds);

    // 创建一个不可变的 Map
    Map<String, String> map = Collections.unmodifiableMap(tempMap);

(OpenFeign)[https://github.com/OpenFeign/feign]

是一个声明式的http客观端,是SpringCloudEureka公司开源的Feign基础上改造而来。

基于SpringMVC的常见注解,实现http请求的发送

  1. 引入依赖

    <!--openFeign-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--负载均衡器-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
  2. 启动OpenFeign

    使用@EnableFeignClients注解

    @EnableFeignClients
    @SpringBootApplication
    public class Application {……}
  3. /client目录下新建ItemClient接口,编写FeignClient

    @FeignClient(value = "服务名,如item-service")
    public interface ItemClient {
    @GetMapping("路由,如/items")
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
    }
  4. 使用FeignClient,实现远程调用

    List<ItemDTO> items = itemClient.queryItemByIds(List.of(1,2,3));

优化-连接池

Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:

  • HttpURLConnection:默认实现,不支持连接池
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池
  1. 引入依赖

    <!--OK http 的依赖 -->
    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    </dependency>
  2. 开启连接池功能

    feign:
    okhttp:
    enabled: true # 开启OKHttp功能

最佳实践

方案一:适合项目结构为Maven聚合,用一个统一的api模块暴露其他微服务需要的dtoapibiz等信息,耦合度比方案一高

方案二:适合项目结构为每个模块是独立的Project,在各自的模块下管理自己的dtoapibiz

方案一

  1. 创建api模块及需要暴露的信息

    --api
    --src
    --main
    --java
    --com.hmall
    --api
    --client
    --dto
    ……
  2. 注入需要的依赖

    例子:

    <dependencies>
    <!--openFeign-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--负载均衡器-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    <dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>1.6.6</version>
    <scope>compile</scope>
    </dependency>
    </dependencies>
  3. 让同父模块下的模块可以扫描到

    <!--feign模块-->
    <dependency>
    <groupId>com.heima</groupId>
    <artifactId>hm-api</artifactId>
    <version>1.0.0</version>
    </dependency>

    在启动类上加声明

    1. @EnableFeignClients(basePackages = "com.hmall.api.client")

    2. @EnableFeignClients(clients = {ItemClient.class})

日志配置

OpenFeign只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。

logging:
level:
com.hmall: debug

而且其日志级别有4级:

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。

  1. api下新建配置类,定义Feign的日志级别

    // package com.hmall.api.config;
    // DefaultFeignConfig

    public class DefaultFeignConfig {
    @Bean
    public Logger.Level feignLogLevel(){
    return Logger.Level.FULL;
    }
    }
  2. 配置类使日志生效

    • 局部生效:在某个FeignClient中配置,只对当前FeignClient生效

      @FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
    • 全局生效:在@EnableFeignClients中配置,针对所有FeignClient生效。

      @EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)