5、Spring-Cloud-声明式调用 Feign(上)

时间:2023-03-09 15:23:10
5、Spring-Cloud-声明式调用 Feign(上)

5.1、写一个 Feign 害户端

新建项目:

5、Spring-Cloud-声明式调用 Feign(上)

5、Spring-Cloud-声明式调用 Feign(上)

依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

关于服务中心使用的是8762(之前的案列写过)

地址:https://www.cnblogs.com/Mrchengs/p/10645911.html

配置文件:
spring.application.name=feign
server.port=
eureka.client.service-url.defaultZone=http://localhost:8762/eureka/
主配置类:

@EnableFeignClients:开启Feign Client功能

@EnableFeignClients(basePackages = "com.cr.eurekafeignclient.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaFeignClientApplication { public static void main(String[] args) {
SpringApplication.run(EurekaFeignClientApplication.class, args);
}
}
上述的三个步骤已经开启了Feign的功能
实现之前eureka client的/port服务的调用

EurekaClientFeign.java

@FeignClient(value = "CLINET",configuration = feignconfig.class)
public interface EurekaClientFeign {
@GetMapping("/port")
String port(); }
@FeignClient:
value:远程调用其他服务的服务名
feignconfig.class为Feign Client的配置类
port():通过Feign来调用CLIENT服务的“/port”的API接口

feignconfig.java

@Configuration
public class feignconfig { @Bean
public Retryer feignRetryer(){
return new Retryer.Default(, TimeUnit.SECONDS.toMillis(1L),);
}
}
配置类:注入一个feignRetryer的Retryer的Bean
注入Bean之后,Feign在远程调用失败之后会进行重试

FeignService.java

@Service
public class FeignService { @Autowired
EurekaClientFeign eurekaClientFeign; public String port(){
return eurekaClientFeign.port();
}
}
在Service层FeignService注入EurekaClientFeign去调用port()方法

FeignController.java

@RestController
public class FeignController {
@Autowired
FeignService feignService; @GetMapping("/feign")
public String sayPort(){
return feignService.port();
}
}
自动注入FeignService 去调用其port()方法
FeignService 通过 EurekaClientFeign远程调用CLIENT服务的API接口“/port”
此时的两个提供者:

5、Spring-Cloud-声明式调用 Feign(上)

分别是8089和8090端口
启动服务:

5、Spring-Cloud-声明式调用 Feign(上)

5、Spring-Cloud-声明式调用 Feign(上)

5、Spring-Cloud-声明式调用 Feign(上)

Feign Client 程调用了 eureka-client 务(8089、8090)两个端口的实例“/port”API接口
Feign Client 有负载均衡的能力。

spring-cloud-starter-openfeign 的porn 文件

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-java8</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
<optional>true</optional>
</dependency>

5.2、FeignClient详解

@FeignClient注解源码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.springframework.cloud.openfeign; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor; @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
@AliasFor("name")
String value() default ""; /** @deprecated */
@Deprecated
String serviceId() 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;
}
FeignClient 注解被@Target(ElementType TYPE)修饰:
表示 FeignClient 注解的作用目标在接口上
@Retention(RetentionPolicy.RUNTll\伍)注解表明该注解会在 lass 字节码文件中存在,
在运行时可以通过反射获取到
@Documented 表示该注解将被包含在 Javadoc 中。
@Feign Client 注解用于创建声明式 API 接口,该接口是RESTful 风格的。
Feign 被设计成插拔式的,可以注入其他组件和 Feign一起使用
最典型的是如果 Ribbon 可用, Feign 会和Ribbon 结合进行负载均衡。
注解中的属性:
---value()和 name() 样,是被调用的服务的 Serviceld
---url ()直接填写硬编码的Uri 地址
---decode404()即 404 是被解码,还是抛异常。
---configuration ()指明 FeignClient 配置类,
    默认的配置类为 FeignClientsConfiguration类,在缺省的情况下 这个类注入
    了默认的 DecoderEncoder、 Contract 等配置的 Bean
---fall back()为配置熔断器的处理类。

5.3、FeignClient的配置

Feign Client 默认的配置类为 FeignClientsConfiguration,这个类在在 pring-cloud-netflix-core的jar下
现这个类注入了很多 Feign 相关的配置 Bean(默认不配置的时候使用默认的)
Decoder、Encoder 、Contract个类在没有Bean被注入的情况下,会自动注入默认配置的 Bean

5、Spring-Cloud-声明式调用 Feign(上)

@Configuration
public class FeignClientsConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Autowired(
required = false
)
private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList();
@Autowired(
required = false
)
private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList();
@Autowired(
required = false
)
private Logger logger; public FeignClientsConfiguration() {
} @Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
} @Bean
@ConditionalOnMissingBean
@ConditionalOnMissingClass({"org.springframework.data.domain.Pageable"})
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
} @Bean
@ConditionalOnClass(
name = {"org.springframework.data.domain.Pageable"}
)
@ConditionalOnMissingBean
public Encoder feignEncoderPageable() {
return new PageableSpringEncoder(new SpringEncoder(this.messageConverters));
} @Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
} @Bean
public FormattingConversionService feignConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
Iterator var2 = this.feignFormatterRegistrars.iterator(); while(var2.hasNext()) {
FeignFormatterRegistrar feignFormatterRegistrar = (FeignFormatterRegistrar)var2.next();
feignFormatterRegistrar.registerFormatters(conversionService);
} return conversionService;
} @Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
} @Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
} @Bean
@ConditionalOnMissingBean({FeignLoggerFactory.class})
public FeignLoggerFactory feignLoggerFactory() {
return new DefaultFeignLoggerFactory(this.logger);
} @Bean
@ConditionalOnClass(
name = {"org.springframework.data.domain.Page"}
)
public Module pageJacksonModule() {
return new PageJacksonModule();
} @Configuration
@ConditionalOnClass({HystrixCommand.class, HystrixFeign.class})
protected static class HystrixFeignConfiguration {
protected HystrixFeignConfiguration() {
} @Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(
name = {"feign.hystrix.enabled"}
)
public Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
}
重写 FeignClientsConfiguration 类中的 Bean
覆盖掉默认的配置 Bean 
从而达到自定义配置的目的
Feign 默认的配置在请求失败后 重试次数为 ,即不重试Retryer.NEVER_RETRY
现在希望在请求失败后能够重试
这时需要写 个配置 FeignConfig 类
在该类中注入Retryer的Bean会覆盖掉默认的 Retryer的Bean
@Configuration
public class feignconfig {
@Bean
public Retryer feignRetryer(){
return new Retryer.Default(, TimeUnit.SECONDS.toMillis(1L),);
}
}