Feign实战-Springboot集成OpenFeign Demo以及参数详解

最近整理一下微服务的文章,先拿一直用的OpenFeign开刀

思考:微服务之间如何方便优雅的实现服务间的远程调用

一、说说openFeign是什么吧?

说到这个,那不得不先说说RPC

1.什么是RPC

RPC 全称是 Remote Procedure Call ,即远程过程调用,其对应的是我们的本地调用。RPC 的目的是:让我们调用远程方法像调用本地方法一样

//本地调用
R result = orderService.findOrderByUserId(id);
//RPC远程调用  orderService为代理对象
R result = orderService.findOrderByUserId(id);

 

RPC框架设计架构

2. 什么是Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可帮助我们更加便捷、优雅地调用HTTP API。

Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。

2.1 OpenFeign和Feign的区别

Feign

Feign是SpringCloud组件中的一个轻量级RESTful的Http服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

OpenFeign

OpenFeign是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

2.2 Ribbon&Feign对比

Ribbon+RestTemplate进行微服务调用

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

//调用方式
String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);

Feign进行微服务调用

@FeignClient(value = "mall-order",path = "/order")
public interface OrderFeignService {
    @RequestMapping("/findOrderByUserId/{userId}")
    public R findOrderByUserId(@PathVariable("userId") Integer userId);
}

//调用
@Autowired
OrderFeignService orderFeignService;
//feign调用
R result = orderFeignService.findOrderByUserId(id);

2.3 Feign的设计架构 

二、Spring Cloud Alibaba快速整合Feign

下面是Springboot集成OpenFeign Demo,完全照着来妥妥的没问题

服务提供者我就不写了,这就是正常的controller,主要是调用者这块,接下来写的也是这个

1.在pom.xml文件中添加以下依赖

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

2.调用端添加启动注解 @EnableFeignClients

@EnableAsync
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class })
@EnableDiscoveryClient
@EnableFeignClients  //扫描和注册feign客户端的beanDefinition
@MapperScan("com.**.**.**.**.mapper")
public class Application {

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

3.编写调用接口+@FeignClient注解

创建一个FeignClient接口,用于定义要调用的远程服务的方法:

@FeignClient(value = "base-application", path = "/base")
@RequestMapping("/api/testDemo")
public interface OpenFeignBaseDemo {

    @PostMapping("/queryList")
    String queryList(@RequestBody JSONObject jsonObject);
}

在上面的代码中,我们使用@FeignClient注解指定了要调用的远程服务的名称。然后,我们定义了一个名为queryList的方法,并使用@PostMapping注解指定了要调用的远程服务的API路径。

4.发起调用,像调用本地方式一样调用远程服务

在其他类中使用OpenFeignBaseDemo 来调用远程服务的方法

@RestController
@RequestMapping("/openFeignDemo")
public class OpenFeignControllerDemo {

    @Autowired
    private OpenFeignBaseDemo openFeignBase;

    @PostMapping(value = "/test", produces = { "application/json;charset=utf-8" })
    public ResponseEntity test(@RequestBody JSONObject jsonObject) {
        //feign调用
        String res = openFeignBase.queryList(jsonObject);
        return new ResponseEntity(res, HttpStatus.OK);
    }

}

5.结果预览

启动两个工程,postmain调用 请求url :localhost:8088/server/openFeignDemo/test。

6.这里我必须强调一下第3步这个参数设置的含义

public @interface FeignClient {
    @AliasFor("name")
    String value() default "";

    String contextId() default "";

    @AliasFor("value")
    String name() default "";

    String qualifier() default "";

    String url() default "";

    boolean decode404() default false;

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

    Class<?> fallback() default void.class;

    Class<?> fallbackFactory() default void.class;

    String path() default "";

    boolean primary() default true;
}

下面就对各个属性进行分析

value、name
value和name的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。

contextId
我们不想将所有的调用接口都定义在一个类中,有一种解决方案就是为每个Client手动指定不同的contextId,这样就不会冲突了。

url
url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择。像调试等场景可以使用。

decode404
当调用请求发生404错误时,decode404的值为true,那么会执行decoder解码,否则抛出异常。

configuration
configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。

fallback
定义容错的处理类,也就是回退逻辑,fallback的类必须实现Feign Client的接口,无法知道熔断的异常信息。

fallbackFactory
也是容错的处理,可以知道熔断的异常信息。

path
path定义当前FeignClient访问接口时的统一前缀,比如接口地址是/user/get, 如果你定义了前缀是user, 那么具体方法上的路径就只需要写/get 即可。

primary
primary对应的是@Primary注解,默认为true,官方这样设置也是有原因的。当我们的Feign实现了fallback后,也就意味着Feign Client有多个相同的Bean在Spring容器中,当我们在使用@Autowired进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@Primary注解就是干这件事情的。

qualifier
qualifier对应的是@Qualifier注解,使用场景跟上面的primary关系很淡,一般场景直接@Autowired直接注入就可以了。

7.报错解决

如果遇到这样的错误:feign.RetryableException: Read timed out executing POST 

可以做如下处理:yaml配置

feign:
  client:
    config:
      default:
        connectTimeout: 1000
        readTimeout: 6000

或者propertis配置

feign.client.config.default.connect-timeout=20000
feign.client.config.default.read-timeout=20000  

https://cloud.spring.io/spring-cloud-openfeign/reference/html/

猜你喜欢

转载自blog.csdn.net/Alex_81D/article/details/133090893
今日推荐