Fegin

是一个http请求调用的轻量级框架,是以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

使用Feign替代RestTemplate发送Rest请求。使之更符合面向接口化的编程习惯。

使用Nacos 注册text、fegin两个服务;使用feign实现服务直接的调用;

dc12f20258cab3a10a0619f8bf14574a.png

Feign服务 

依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
  <version>版本号</version>
</dependency>

在启动类上加入 @EnableFeignClients,表示开启Feign 

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class, args);
    }
}

@FeignClient

  • name/value:指定FeignClient的名称,如果指定了注册中心,指注册的服务名称。
  • url:可以手动指定@FeignClient调用的地址。
  • contextId:指定beanID。
  • decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException。
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
  • path: 定义当前FeignClient的统一前缀
@FeignClient(
        value = "text"
        // url = "127.0.0.1:8090" 通过url指定服务地址访问也是可以的
)
public interface TextClient {

    @GetMapping("/text/findOrderDetailById")
    OrderDetail findOrderDetailById(@RequestParam String detailId);
}

服务调用

@RestController
@RequestMapping("/fegin")
public class FeginController {

    @Autowired
    private TextClient textClient;

    @GetMapping("/findOrderDetailById")
    public OrderDetail findOrderDetailById(@RequestParam("detailId") String detailId){
        return textClient.findOrderDetailById(detailId);
    }

}

 Text服务

@RestController
@RequestMapping("/text")
public class TextController {

    @GetMapping("/findOrderDetailById")
    public OrderDetail findOrderDetailById(@RequestParam("detailId") String detailId){
        return new OrderDetail(detailId);
    }
}

测试

fed82c55cce5308ed19462f44458e41c.png

configuration:Feign配置类,可以自定义Feign配置

23e4d4e3aacc079e47a410a414934949.png

Retryer:

  1. Feign默认配置是不走重试策略的,当发生RetryableException异常时直接抛出异常。
  2. 并非所有的异常都会触发重试策略,只有 RetryableException 异常才会触发异常策略。
  3. 在默认Feign配置情况下,只有在网络调用时发生 IOException 异常时,才会抛出 RetryableException,也是就是说链接超时、读超时等不不会触发此异常。

因此常见的 SocketException、NoHttpResponseException、UnknownHostException、HttpRetryException、SocketConnectException、ConnectionClosedException 等异常都可触发Feign重试机制。
注:常见的还有 SocketTimeoutException、TimeoutException、ReadTimeoutException、WriteTimeoutException 等都不属于IO异常,因为不会触发Feign重试机制。

@Slf4j
public class FeginConfig {

    /**
     * 自定义重试
     * maxAttempts:最多请求次数
     * period:发起当前请求的时间间隔,单位毫秒
     * maxPeriod:发起当前请求的最大时间间隔,单位毫秒
     * @return
     */
    @Bean
    public Retryer feginRetryer(){
        // 默认最大请求次数为5,初始间隔时间为100ms,下次间隔时间1.5倍递增,重试间最大间隔时间为1s,
//        return new Retryer.Default();
        return new Retryer.Default(1000, 0, 3);
    }

    /**
     * 自定义错误码
     * 当feign调用返回HTTP报文时,会触发这个方法,方法内可以获得HTTP状态码,可以用来定制一些处理逻辑等等
     * @return
     */
    @Bean
    public ErrorDecoder feginErrorDecoder() {
        return (key, response) -> {

            switch (response.status()) {
                case 404:
                    log.error("请求Text服务404异常,返回:{}", response.body());
                    break;
                case 503:
                    log.error("请求Text服务503异常,返回:{}", response.body());
                    break;
                default:
                    log.error("请求Text服务异常,返回:{}", response.body());
            }

            // 其他异常交给Default去解码处理
            // 这里使用单例即可,Default不用每次都去new
            return new ErrorDecoder.Default().decode(key, response);
        };
    }

}

自定义重试类

@Slf4j
@Component
@NoArgsConstructor
public class CustomRetryer implements Retryer{

    private int retryMaxAttempt;

    private long retryInterval;

    private int attempt = 1;


    public CustomRetryer(int retryMaxAttempt, Long retryInterval) {
        this.retryMaxAttempt = retryMaxAttempt;
        this.retryInterval = retryInterval;
    }

    @Override
    public void continueOrPropagate(RetryableException e) {
        log.info("Feign retry attempt {} due to {} ", attempt, e.getMessage());

        if(attempt++ == retryMaxAttempt){
            throw e;
        }
        try {
            Thread.sleep(retryInterval);
        } catch (InterruptedException ignored) {
            Thread.currentThread().interrupt();
        }

    }

    @Override
    public Retryer clone() {
        return new CustomRetryer(6, 2000L);
    }
}

全局配置

feign:
	client:
		config:
		# 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
		default:
			#  日志级别
			loggerLevel: FULL
			# 连接超时
			connectTimeout: 1000
			# 读取超时
			readTimeout: 1000
			# 自定义重试
            retryer: com.Fegin.config.CustomRetryer

<!-- feign:
  client:
    config:
      defalut: # feign请求默认配置
        connectTimeout: 2000
        readTimeout: 3000
      fiegnName: # fiegnName服务请求的配置,优先defalut配置。
        connectTimeout: 5000 # 链接超时时间
        readTimeout: 5000  # 请求
        loggerLevel: full   # 日志级别
        errorDecoder: com.example.SimpleErrorDecoder #异常处理
        retryer: com.example.SimpleRetryer # 重试策略
        defaultQueryParameters: # 默认参数条件
          query: queryValue
        defaultRequestHeaders:  # 默认默认header
          header: headerValue
        requestInterceptors:    # 默认拦截器
          - com.example.FooRequestInterceptor
          - com.example.BarRequestInterceptor
        decode404: false   #404响应 true-直接返回,false-抛出异常       
        encoder: com.example.SimpleEncoder  #传输编码
        decoder: com.example.SimpleDecoder  #传输解码
        contract: com.example.SimpleContract #传输协议 -->

fallback和fallbackFactory 是Fegin两种降级的方式。不能同时使用。

OpenFegin 3.0 以前 集成了hystrixribbon,3.0以后去除了。这时使用fallbackFactory会失效。

需要单独引入hystrix

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>2.2.10.RELEASE</version>
</dependency>

配置文件 feign.hystrix.enabled 不见了改成 fegin.circuitbreaker.enabled

feign:
  circuitbreaker:
    enabled: true
@Slf4j
@Component
public class TextClientFallbackFactory implements FallbackFactory<TextClient> {

    @Override
    public TextClient create(Throwable cause) {
        return new TextClient() {
            @Override
            public OrderDetail findOrderDetailById(String detailId) {
                log.info("调用{Text}失败,回调:detailId:{}", detailId );
                return new OrderDetail(detailId);
            }
        };
    }
}

测试

44daacf1a8c029f215a38ffa0773373c.png

也可以集成阿里的sentinel。

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置文件开启

feign:
  sentinel:
    enabled: true

测试

a8ec9a96411367d7673958888a078198.png

sentinel和Hystrix区别

ae32b8fdf4c6b6140defad6d867e1ad5.png

使用Fegin实现文件上传

@RestController
@RequestMapping("/fegin")
public class FeginController {

    @Autowired
    private TextClient textClient;

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file){
        return textClient.upload(file);
    }

}

文件上传

文件属性需要使用 @RequestPart 属性,而且在请求中添加 consumes = MediaType.MULTIPART_FORM_DATA_VALUE ,

文件表单上传请求通常使用的ContentType为 multipart/form-data ,通过以上直接调用feign的方式即可实现feign 文件上传。

@RequestPart:用在multipart/form-data表单提交请求的方法上。支持的请求方法的方式MultipartFile,属于Spring的MultipartResolver类。这个请求是通过http协议传输的。

@RequestParam也同样支持multipart/form-data请求。

他们最大的不同是,当请求方法的请求参数类型不再是String类型的时候。@RequestParam适用于name-valueString类型的请求域,@RequestPart适用于复杂的请求域(像JSON,XML)。

produces:它的作用是指定返回值类型,不但可以设置返回值类型还可以设定返回值的字符编码;

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

@FeignClient(
        value = "text",
        configuration = FeginConfig.class,
        fallbackFactory = TextClientFallbackFactory.class
)
public interface TextClient {
    
    @PostMapping(value = "/text/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
    String upload(@RequestPart("file") MultipartFile file);
}

 Text服务

@RestController
@RequestMapping("/text")
public class TextController {

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file){
        return file.getName();
    }
}

 测试

3a371cadf0424edf3333e4b0c5c1ae86.png

 

12-18 169
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值