SpringCloud--OpenFeign解析

一、OpenFeign简介

OpenFeign是一个声明式的Web服务客户端,它简化了与HTTP API的通信。它的底层原理主要基于Java的反射和动态代理,并且通过利用Spring AOP 框架、RestTemplate、Ribbon 和 Hystrix 等组件,将复杂的 HTTP 调用封装起来,使得开发者能够像调用本地服务一样使用远程服务。

二、OpenFeign 使用步骤

假设有个下单服务为orderService需要调用库存服务stockService中的接口查询商品的库存量。

  1. 首先在两个服务的pom.xml文件中引入OpenFeign 组件。
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 先在orderService创建一个查询商品库存的接口,这个接口上面使用了一个@FeignClient注解标注,注解里面的name属性指定了要调用的服务名,表明该远程接口属于哪个服务。接口里面的方法上面使用了@RequestMapping注解标注,该注解里面指定了要访问的接口路径。
@FeignClient(name = "stock-service")
public interface StockServiceFeign {
    /**
     * 获取商品信息
     *
     */
    @RequestMapping("/stock/getStockInfo")
    CommonResult<Page<SysRole>> getStockInfo(@RequestParam String stockId);
}
  1. 在orderService的启动类上添加@EnableFeignClients注解,该注解表明在服务启动后开启远程调用。
@EnableFeignClients
@SpringBootApplication
public class NjhGatewayApplication {

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

  1. 最后到stockService服务中定义一个接口去实现具体的功能,并保证接口地址以及入参与orderService刚定义的接口一致。
@RestController
public class StockController {
	@Autowired StockService;
	
    @RequestMapping("/stock/getStockInfo")
    public R getStockInfo(@RequestParam String stockId) {
       return StockService.getStockInfo(stockId);
    }
}

三、实现原理

从上面例子可以看出OpenFeign 使用起来还是很简单方便,但是其底层原理就没那么简单了。其核心的处理逻辑就是使用Spring的AOP动态代理技术,对所有被 @FeignClient 注解修饰的接口生成一个动态代理类,在这个代理类中会将注解中的服务的名称、接口类型、访问路径转化成一个远程服务调用的 Request请求,并发送给目标服务。转化后的Request请求格式类似GET http://stock-service/stock/getStockInfo/10001 HTTP/1.1,下面看下主要的处理流程:

  1. 创建代理对象:当你定义一个使用了 @FeignClient 注解的接口时,OpenFeign 会在运行时为这个接口创建一个代理对象。这个代理对象用于处理对远程服务的调用。
  2. 解析注解:在运行时,OpenFeign 会解析 @FeignClient 注解,确定要连接的服务名称。如果使 用了服务注册中心(如 Eureka),服务名称会被用来查找服务实例。
  3. 路由匹配:对于每个接口方法,OpenFeign 会创建一个映射,将方法路径(如果提供的话)和 HTTP 请求方法(如 GET、POST 等)与服务端的 API 路径进行匹配。
  4. 构建请求:当代理对象被调用时,OpenFeign 会构建一个 HTTP 请求,这个请求包含了方法参数作为请求体或查询参数。编码器将这些参数转换为适用于 HTTP 传输的格式。
  5. HTTP 调用:使用默认的或自定义的 HTTP 客户端,OpenFeign 发送 HTTP 请求到远程服务。如果使用了 Ribbon,它会进行负载均衡来决定请求发送到哪个服务实例。
  6. 接收响应:HTTP 客户端接收远程服务的响应,并将其传递给解码器。
  7. 解码响应:解码器将 HTTP 响应体解码为方法可以接受的参数或返回值。如果响应是一个 JSON 或 XML 字符串,解码器会将其转换为 Java 对象。
  8. 处理异常:如果在请求过程中发生错误,例如连接失败或解码错误,OpenFeign 会将异常传递给调用者。开发者可以定义错误处理策略来处理这些异常。
  9. 返回结果:最终,解码后的结果会作为方法的返回值返回给调用方。

四、源码解析

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] defaultConfiguration() default {};

    Class<?>[] clients() default {};
}

(1)@EnableFeignClients注解中的basePackages属性来设置包扫描的范围,从中找出所有带有@FeignClient 注解的类、接口,并将它们注册为Feign客户端。

@EnableFeignClients(basePackages = "com.jackson0714.passjava.member.feign")

(2)进入@EnableFeignClients注解可以看到里面使用了一个@Import({FeignClientsRegistrar.class})注解,里面还导入了FeignClientsRegistrar.class类,主要负责将Feign Client的Bean注册到Spring的IOC容器中。
SpringCloud--OpenFeign解析_第1张图片
(3)registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)方法主要用于注册Bean定义。
在这里插入图片描述
(4)getBasePackages(AnnotationMetadata importingClassMetadata)方法将扫描到的所有@FeignClient 注解的元数据,从这些元数据中提取出基础包名,并将它们作为一个Set集合返回。
SpringCloud--OpenFeign解析_第2张图片

你可能感兴趣的:(spring,cloud,spring,cloud,chrome,spring)