重要类与接口解析
1. @EnableFeignClients
该注解中一共有5个属性:
我们依次看,这些属性流程分析的时候都会用到:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* {@link #basePackages()}属性的别名。允许更简洁的注释
*
* declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
* {@code @ComponentScan(basePackages="org.my.pkg")}.
* @return the array of 'basePackages'.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components.
* 扫描带注解组件的基本包路径
* <p>
* {@link #value()} is an alias for (and mutually exclusive with) this attribute.
* value()是此属性的别名(并与其互斥)。
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
* 使用{@link #basePackageClasses()}作为基于字符串的包名的类型安全替代方案。
*
* @return the array of 'basePackages'.
*/
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.
* 类型安全的{@link #basePackages()}的替代方案,用于指定要扫描的包以寻找带注解的组件。
* 每个指定类的包将被扫描。
* <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'.
* 考虑在每个包中创建一个特殊的无操作标记类或接口,
* 该标记类或接口除了被该属性引用之外没有其他用途。
*
* 可以用类或接口的方式代替字符串方式指定包名。
*/
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}.
* 一个自定义的@Configuration用于所有 feign 客户端。可以包含组成客户端的各个组件的重
* 写@Bean定义,例如{@link feign.codec。解码器},{@link feign.codec。编码器},
* {@link feign.Contract}。
*
* feign clients的全局配置,配置的是构成feign client的组件的具体实现类,这些类的实例最终
* 会放到每个feign client专门的一个子容器中
*
* @see FeignClientsConfiguration for the defaults
* @return list of default configurations
*/
Class<?>[] defaultConfiguration() default {};
/**
* List of classes annotated with @FeignClient. If not empty, disables classpath
* scanning.
* 用@FeignClient注解的类列表。如果不为空,则禁用类路径扫描。
*
* 通过该属性直接指定要加载哪些@FeignClient接口
* 用这个属性,就不会进行包路径扫描了
* @return list of FeignClient classes
*/
Class<?>[] clients() default {};
}
defaultConfiguration属性可以为所有feign客户端配置默认的全局配置,可以配置如下组件:
-
Decoder
-
Encoder
-
Contract
就是这个接口,允许OpenFeign 支持处理 SpringMVC 相关的注解:
有兴趣自己看吧。
2. @FeignClient
快速入门第三章 OpenFeign 曾用的Demo:
看到该注解中属性还是比较多的:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
/**
* 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}.
* 带有可选协议前缀的服务名称。{@link #name() name}的同义词。无论是否提供url,
* 都必须为所有客户端指定名称。可以指定为属性键,例如:${propertyKey}。
*
* 例如http://xxxxx:port/aaa/bb/cc xxxxx就是服务名称
*
* 属性键$ {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
* 带有可选协议前缀的服务id。{@link #value() value}的同义词。
* 过时了,使用{@link #name() name}代替
*
* @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.
* 如果存在,它将被用作bean名,代替name属性,但不会用作服务id。
*
* @return bean name instead of name if present
*/
String contextId() default "";
/**
* @return The service id with optional protocol prefix. Synonym for {@link #value()
* value}.
* 带有可选协议前缀的服务id。{@link #value() value}的同义词。
*/
@AliasFor("value")
String name() default "";
//--------- 分割线上面这些属性作用都是一样的,代表微服务名称、服务ID -----------
/**
* @return the <code>@Qualifier</code> value for the feign client.
* feign client的@Qualifier值。
* 根据Class Type注入,如果存在多个会报错,就需要根据名称注入@Qualifier可以指定名称
*/
String qualifier() default "";
/**
* @return an absolute URL or resolvable hostname (the protocol is optional).
* 绝对URL或可解析主机名(协议是可选的)。
*
* 配置这个相当于直连方式,例如url="localhost:8080"
* 这样就不会根据微服务名称负载均衡了
*/
String url() default "";
/**
* @return whether 404s should be decoded instead of throwing FeignExceptions
* 如果发生FeignExceptions是否需要返回404
*/
boolean decode404() default false;
/**
* A custom <code>@Configuration</code> 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}.
* 一个自定义的@Configuration用于feign client。可以包含组成客户端的组件的重写@Bean定义,
* 例如{@link feign.codec。解码器},{@link feign.codec。编码器},{@link feign.Contract}。
*
* 这个配置相当于是局部配置,某一个feign client专门的配置
*
* @see FeignClientsConfiguration for the defaults
* @return list of configurations for feign client
*/
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.
* 指定Feign client接口的服务降级类。服务降级类必须实现由该注解注释的接口,
* 并且必须是一个有效的spring bean。
*
* @return fallback class for the specified Feign client interface
*/
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.
* 为指定的Feign client接口定义一个服务降级工厂。服务降级工厂必须生成服务降级类的实例,
* 这些实例实现了由{@link FeignClient}注释的接口。服务降级工厂必须是一个有效的spring bean。
*
* @see feign.hystrix.FallbackFactory for details.
* @return fallback factory for the specified Feign client interface
*/
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>.
* 所有方法级映射使用的路径前缀。可与或不与@RibbonClient一起使用。
*/
String path() default "";
/**
* @return whether to mark the feign proxy as a primary bean. Defaults to true.
* 是否将feign代理标记为主bean。默认值为true。
*
* 和@Primary注解类似,同一个接口多个实现类中
* 根据类型注入时候会首选被@Primary标记的实现类
*
* 每个feign client接口都会为其生成一个代理类,这里是为这个代理类标记为Primary
*/
boolean primary() default true;
}
3. FeignClientSpecification 类
FeignClientSpecification 是一个 Feign Client 的生成规范,可以简单理解为是@EnableFeignClients注解和@FeignClient注解解析后数据存放的一个类,通过bean扫描,将扫描到的@EnableFeignClients注解的defaultConfiguration属性、@FeignClient注解的configuration属性
维护在这个类中,将来初始化FeignClient子容器时会将这些类实例化到子容器,这些配置类实例都是Feign Cient构建所依赖的组件:
class FeignClientSpecification implements NamedContextFactory.Specification {
//feignClient的名称,就是服务名、服务id
private String name;
//当前feignClient的配置类
private Class<?>[] configuration;
FeignClientSpecification() {
}
FeignClientSpecification(String name, Class<?>[] configuration) {
this.name = name;
this.configuration = configuration;
}
...
}
4. FeignContext 类
FeignContext 是 OpenFeign 的上下文对象,也是 Feign Client 的工厂类。
解释:就是一个Feign Client的工厂,生成Feign Client实例的。它会为每一个要创建的feign客户端(即feign client 接口)都创建一个子容器,并在子容器中注册FeignClient规范类中的配置类,这些类实例都是Feign Client创建所依赖的一些组件。而子容器的父容器就是整个应用的Spring容器。
重点要看一下父类:
configurations 维护的就是不同Feign Client名称对应的FeignClient规范。
其中包含了一个特殊的,全局的FeignClient规范:
- 全局的FeignClient规范:key 为 default + 当前启动类的全限定性类名,value 就是FeignClientSpecification,其configuration属性是@EnableFeignClients 中的 defaultConfiguration 属性值。这个 Entry 只有一个。
就是全局的FeignClient规范
。 - 局部的FeignClient规范: key 为服务id,服务名称,value 就是FeignClientSpecification,其configuration属性是@FeignClient 的 configuration 属性值。当前应用中有多少个这个 Feign Client,那么这里就会包含多少个这种 Entry。
就是每个FeignClient专门的FeignClient规范
5. BeanDefinition 接口
BeanDefinition 是一个 Bean 定义器,这个是Spring框架中的,OpenFeign 和 Spring 整合了嘛,初始化阶段扫描到的所有组件等都是作为BeanDefinition在Spring容器中的。
Spring解析xml时就会把一个<bean/>标签解析成一个BeanDefinition实例,最终通过BeanDefintion在Spring容器中生成一个Bean。
6. BeanDefinitionRegistry 接口
BeanDefinitionRegistry 是一个 BeanDefinition 注册表。