0. 环境
- nacos版本:1.4.1
- Spring Cloud : Hoxton.SR9(
没用2020.0.2版本后面说明
) - Spring Boot :2.4.4
- Spring Cloud alibaba: 2.2.5.RELEASE
- Spring Cloud openFeign 2.2.2.RELEASE
测试代码:github.com/hsfxuebao/s…
2020.0.X版本
开始的OpenFeign底层不再使用Ribbon了
1. 下载
github地址:github.com/spring-clou…
由于是maven工程,直接导入IDEA中就可以了
2. 核心类介绍
2.1 @EnableFeignClients
// @EnableFeignClients注解用来启动FeignClient,以支持Feign。
// 该注解可以通过配置,扫描指定位置的@FeignClient注解声明的Feign客户端接口
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
// value和basePackage具有相同的功能,其中value是basePackage的别名
// value和basePackage只能同时使用一个
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
* {@code @ComponentScan(basePackages="org.my.pkg")}.
* @return the array of 'basePackages'.
*/
// 为basePackages属性的别名,允许使用更简洁的书写方式。例如:@EnableFeignClients({"com.cd", "com.ad"})
String[] value() default {};
/**
* Base packages to scan for annotated components.
* <p>
* {@link #value()} is an alias for (and mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
* @return the array of 'basePackages'.
*/
// 设置自动扫描带有@FeignClient注解的基础包路径。例如 @EnableFeignClients(basePackages = {"com.cd", "com.ad"})
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return the array of 'basePackageClasses'.
*/
// 该属性是basePackages属性的安全替代属性。该属性将扫描指定的每个类所在的包下面的所有被@FeignClient修饰的类;
// 这需要考虑在每个包中创建一个特殊的标记类或接口,该类或接口除了被该属性引用外,没有其他用途
Class<?>[] basePackageClasses() default {};
/**
* A custom <code>@Configuration</code> for all feign clients. Can contain override
* <code>@Bean</code> definition for the pieces that make up the client, for instance
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
*
* @see FeignClientsConfiguration for the defaults
* @return list of default configurations
*/
// 该属性用来自定义所有Feign客户端的配置,使用@Configuration进行配置。
// 当然也可以为某一个Feign客户端进行配置。具体配置方法见@FeignClient的configuration属性。
Class<?>[] defaultConfiguration() default {};
/**
* List of classes annotated with @FeignClient. If not empty, disables classpath
* scanning.
* @return list of FeignClient classes
*/
// 设置由@FeignClient注解修饰的类列表。如果clients不是空数组,则不通过类路径自动扫描功能来加载FeignClient
// 例如 @EnableFeignClients(clients = {SchedualService.class})
// 上面代码中引入FeignClient客户端SchedualService,且也只引入该FeignClient客户端。
Class<?>[] clients() default {};
}
复制代码
2.2 @FeignClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
// name 和 value 两个属性等价,至少要配置一个
/**
* The name of the service with optional protocol prefix. Synonym for {@link #name()
* name}. A name must be specified for all clients, whether or not a url is provided.
* Can be specified as property key, eg: ${propertyKey}.
* @return the name of the service with optional protocol prefix
*/
@AliasFor("name")
String value() default "";
/**
* The service id with optional protocol prefix. Synonym for {@link #value() value}.
* @deprecated use {@link #name() name} instead
* @return the service id with optional protocol prefix
*/
@Deprecated
String serviceId() default "";
/**
* This will be used as the bean name instead of name if present, but will not be used
* as a service id.
* @return bean name instead of name if present
*/
// 别名,假设一个User服务有两个FeignClient,都需要调用Product服务, 因为name属性值一样,所以需要通过配置contextId来区分,否则启动项目时会报错
String contextId() default "";
/**
* @return The service id with optional protocol prefix. Synonym for {@link #value()
* value}.
*/
@AliasFor("value")
String name() default "";
/**
* @return the <code>@Qualifier</code> value for the feign client.
*/
// 返回默认值=contextId+“FeignClient”。
String qualifier() default "";
/**
* @return an absolute URL or resolvable hostname (the protocol is optional).
*/
// 请求地址, 没配置的话, 会把name/value的属性值当成服务名进行调用, 配置的话则使用url的值
String url() default "";
/**
* @return whether 404s should be decoded instead of throwing FeignExceptions
*/
// 当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
boolean decode404() default false;
/**
* A custom configuration class for the feign client. Can contain override
* <code>@Bean</code> definition for the pieces that make up the client, for instance
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
*
* @see FeignClientsConfiguration for the defaults
* @return list of configurations for feign client
*/
// Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
Class<?>[] configuration() default {};
/**
* Fallback class for the specified Feign client interface. The fallback class must
* implement the interface annotated by this annotation and be a valid spring bean.
* @return fallback class for the specified Feign client interface
*/
// 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
Class<?> fallback() default void.class;
/**
* Define a fallback factory for the specified Feign client interface. The fallback
* factory must produce instances of fallback classes that implement the interface
* annotated by {@link FeignClient}. The fallback factory must be a valid spring bean.
*
* @see feign.hystrix.FallbackFactory for details.
* @return fallback factory for the specified Feign client interface
*/
// 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
Class<?> fallbackFactory() default void.class;
/**
* @return path prefix to be used by all method-level mappings. Can be used with or
* without <code>@RibbonClient</code>.
*/
// 所有方法级映射使用的路径前缀
String path() default "";
/**
* @return whether to mark the feign proxy as a primary bean. Defaults to true.
*/
// 是否将外部代理标记为主bean。默认为true。
boolean primary() default true;
}
复制代码
2.3 FeignClientSpecification
FeignClientSpecification
是 Feign Client 生成规范:
2.4 FeignContext
FeignContext
是一个为 Feign Client
创建所准备的上下文对象
// FeignContext 是一个为 Feign Client 创建所准备的上下文对象
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}
}
复制代码
其父类为:
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
implements DisposableBean, ApplicationContextAware {
private final String propertySourceName;
private final String propertyName;
// todo 该 map 的 key 为 FeignClient 的名称(其所要调用的微服务名称), value 是组装这个
// FeignClient 所必须的组件所在的 Spring 子容器
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
// 这个map中存放的是@EnableFeignClients与@FeignClient两个注解中的configuration属性值。
// 这个属性值只有两类:
// 第一类只有一个,其 key 为字符串 default + 当前启动类的全限定性类名 ,例如:
// default.com.abc.ConsumerFeign8080, value 为@EnableFeignClients 的 defaultConfiguration属性值
// 第二类有多个,其 key 为当前@FeignClient 的名称, value 为这个注解的 configuration 属性值
private Map<String, C> configurations = new ConcurrentHashMap<>();
private ApplicationContext parent;
private Class<?> defaultConfigType;
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName,
String propertyName) {
this.defaultConfigType = defaultConfigType;
this.propertySourceName = propertySourceName;
this.propertyName = propertyName;
}