一 基本原理图
feign的注册:
- 客户端在引入EnableFeignClients时会通过FeignClientsRegistrar完成feign的客户端的注册
- FeignClientsRegistrar中通过registerDefaultConfiguration注册默认配置
- FeignClientsRegistrar中通过registerFeignClients注册Feign的客户端
feign的代理生成:
- spring在刷新容器时触发FeignClientfactory中的getObet
- 在getObject中获得feignContext,在feignContex中包含了很多feign的日志,解析器等配置
- 然后根据Feign接口 的URL(要么通过@FeignClient(url=“”)指定,如果没指定,就根据@FeignClient(value=“服务名”)拼接) 生成负载均衡代理类
- 通过loadBalance方法是如何生成负载均衡代理类的
- ReflectiveFeign通过Proxy.newProxyInstance为Feign接口生成代理
二 源码分析
2.1 feign的注册
Feign是如何对客户端接口进行注册到Spring容器中的,从==@EnableFeignClients==标签入手
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
该注解导入了FeignClientsRegistrar,他是一个客户端的注册器
主要是通过registerDefaultConfiguration和registerFeignClients完成feign客户端的相应配置
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {
// patterned after Spring Integration IntegrationComponentScanRegistrar
// and RibbonClientsConfigurationRegistgrar
private ResourceLoader resourceLoader;
private Environment environment;
public FeignClientsRegistrar() {
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
//registerBeanDefinitions方法是ImportBeanDefinitionRegistrar接口中的用来注册Bean到Spring容器的方法
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//注册默认的配置
registerDefaultConfiguration(metadata, registry);
//注册Feign的客户端
registerFeignClients(metadata, registry);
}
2.1.1 feign默认配置的注册
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//得到@EnableFeignClients注解的原始信息
Map<String, Object> defaultAttrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
//是否配置了@EnableFeignClients(defaultConfiguration=)默认配置
//使用的类型是FeignClientsConfiguration
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
//处理类型,以default开头
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
//注册默认配置,name 默认以 default 开头,后续会根据名称选择配置
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
上面这个方法在为==@EnableFeignClients(defaultConfiguration=)==默认配置类做注册,一般可以不配置该属性
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
//创建一个BeanDefinitionBuilder
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
//添加参数,把配置类交给builder
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
//注册了Bean到Spring容器
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
在调用registerClientConfiguration将其转换为FeignClientSpecification注册到spring容器,然后再FeignContext初始化是通过setconfig注册到上下文中
2.1.2 Feign的客户端注册
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//ClassPathScanningCandidateComponentProvider是用来扫Feign描客户端接口的
ClassPathScanningCandidateComponentProvider scanner = getScanner();
//resourceLoader是用来加载类资源的
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
//获取@EnableFeignClients注解元数据
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
//类型过滤器,过滤FeignClient
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
//检查是否配置clients属性
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
//默认走这里
//如果没有配置@EnableFeignClient(clients={})属性,就获取basePackages属性
//给扫描添加includeFilters过滤器,目的是为了扫描@FeignClient注解
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = getBasePackages(metadata);
}
else {
//如果配置了clients就把 clients的包添加到扫描器中
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(
new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}
for (String basePackage : basePackages) {
//把basePackage下的注解了@FeignClient的接口封装成BeanDefinition
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
//获取每个接口的注解元数据
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
//获取@FeignClient注解上的属性
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
//获取客户端名字
String name = getClientName(attributes);
//获取@FeignClient注解的configuration配置,对配置进行注册
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//注册客户端接口feignClient
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
上面代码主要扫描了注解了@FeignClient的接口,会扫描到很多的接口,然后做2个事情
- 将其配置类通过registerClientConfiguration注册到容器中,这个方法在刚才已经分析过了,这里是第二次调用
- 通过registerFeignClient注册FeignClient接口到容器,内部会生成接口的代理类
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
//获取到组合的Feign接口类名
String className = annotationMetadata.getClassName();
//FeignClientFactoryBean是用用来创建FeignClient接口的,
//这里要对Feign接口进行代理,使用的是FeignClientFactoryBean
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
//校验@FeignClient相关属性
validate(attributes);
//封装相关的属性到definition
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = name + "FeignClient";
//得到BeanDefinition对象,它是对Feign客户端的Bean的定义对象,基于FeignClientFactoryBean
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
//将BeanDefinition加入到spring容器
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
2.2 feign代理生成
通过上面的分析我们可以知道FeignClientFactoryBean中将用于feign代理类的生成
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
ApplicationContextAware {
//Feign接口类型
private Class<?> type;
//Fiegn客户端名字/请求的服务名
private String name;
//请求的url
private String url;
private String path;
private boolean decode404;
private ApplicationContext applicationContext;
private Class<?> fallback = void.class;
//降级工厂
private Class<?> fallbackFactory = void.class;
....省略....
@Override
public Object getObject() throws Exception {
//获取Feign的上下文,在Feign的初始化一节有说道
FeignContext context = applicationContext.getBean(FeignContext.class);
//调用feign方法得到Builder构造器,用来生成feign
//开启Hystrix使用的是HystrixFeign.Builder
//否则使用的是feign.Feign.Builder
Feign.Builder builder = feign(context);
//如果没有url,即没有指定@FeignClient(url=""),就根据服务名拼接url
if (!StringUtils.hasText(this.url)) {
String url;
//拼接请求的url如:http://user-server
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
//生成负载均衡代理类
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
//如果配置了@FeignClient(url=""),生成默认代理
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
// not load balancing because we have a url,
// but ribbon is on the classpath, so unwrap
client = ((LoadBalancerFeignClient)client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
FeignClientFactoryBean实现了FactoryBean,getObject方法即是用来创建FeignClient实例的
- 该方法授权通过ApplicationContext得到FeignContext上下文
- 然后在从FeignContext上下文中得到Feign.Builder,它是用来构建Feign客户端代理类的
- 然后根据Feign接口 的URL(要么通过@FeignClient(url=“”)指定,如果没指定,就根据@FeignClient(value=“服务名”)拼接) 生成负载均衡代理类
2.2.1 Feign.Builder
Feign.Builder中封装了Feign的日志注解,编码器,解码器,拦截器等等,这些东西是在FeignClientsConfiguration中被创建的
public static class Builder {
//请求拦截器
private final List<RequestInterceptor> requestInterceptors = new ArrayList();
...省略...
public Builder() {
//Feign的日志打印级别,默认不打印
this.logLevel = Level.NONE;
this.contract = new Default();
this.client = new feign.Client.Default((SSLSocketFactory)null, (HostnameVerifier)null);
//重试策略
this.retryer = new feign.Retryer.Default();
this.logger = new NoOpLogger();
//编码器
this.encoder = new feign.codec.Encoder.Default();
//解码器
this.decoder = new feign.codec.Decoder.Default();
//错误解码器
this.errorDecoder = new feign.codec.ErrorDecoder.Default();
this.options = new Options();
//方法调用工厂
this.invocationHandlerFactory = new feign.InvocationHandlerFactory.Default();
}
//设置日志级别
public Feign.Builder logLevel(Level logLevel) {
this.logLevel = logLevel;
return this;
}
public Feign.Builder contract(Contract contract) {
this.contract = contract;
return this;
}
public Feign.Builder client(Client client) {
this.client = client;
return this;
}
public Feign.Builder retryer(Retryer retryer) {
this.retryer = retryer;
return this;
}
public Feign.Builder logger(Logger logger) {
this.logger = logger;
return this;
}
public Feign.Builder encoder(Encoder encoder) {
this.encoder = encoder;
return this;
}
public Feign.Builder decoder(Decoder decoder) {
this.decoder = decoder;
return this;
}
public Feign.Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
this.decoder = new Feign.ResponseMappingDecoder(mapper, decoder);
return this;
}
public Feign.Builder decode404() {
this.decode404 = true;
return this;
}
public Feign.Builder errorDecoder(ErrorDecoder errorDecoder) {
this.errorDecoder = errorDecoder;
return this;
}
public Feign.Builder options(Options options) {
this.options = options;
return this;
}
public Feign.Builder requestInterceptor(RequestInterceptor requestInterceptor) {
this.requestInterceptors.add(requestInterceptor);
return this;
}
//添加Feign的拦截器
public Feign.Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
this.requestInterceptors.clear();
Iterator var2 = requestInterceptors.iterator();
while(var2.hasNext()) {
RequestInterceptor requestInterceptor = (RequestInterceptor)var2.next();
this.requestInterceptors.add(requestInterceptor);
}
return this;
}
public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
this.invocationHandlerFactory = invocationHandlerFactory;
return this;
}
public <T> T target(Class<T> apiType, String url) {
return this.target(new HardCodedTarget(apiType, url));
}
//这个方法挺重要的,它是用来构建FeignClient的代理类的
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
//注意:这里使用的是ReflectiveFeign作为Feign的默认实现
//创建Feign接口的代理就是ReflectiveFeign搞定的
public Feign build() {
Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404);
ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory);
}
}
2.2.2 FeignClientsConfiguration
@Configuration
public class FeignClientsConfiguration {
//Feign的消息转换器
@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;
//解码器
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}
//编码器
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return 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();
for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) {
feignFormatterRegistrar.registerFormatters(conversionService);
}
return conversionService;
}
//如果开启了Hystrix,那么使用的是HystrixFeign.builder();
//而不是Feign.Builder
@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
//重试策略
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
//注册Feign.Builder
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
//日志工厂
@Bean
@ConditionalOnMissingBean(FeignLoggerFactory.class)
public FeignLoggerFactory feignLoggerFactory() {
return new DefaultFeignLoggerFactory(logger);
}
}
2.2.3 loadBalance生成feign负载均衡代理
从FeignContext上下文中获取到LoadBalancerFeignClient负载客户端设置给Feign.Builder ,然后从FeignContext上下文得到Targeter,通过Targeter.target方法创建实例,底层通过Feign.newInstance方法完成实例创建,默认实现是ReflectiveFeign完成创建
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
//从上下文对象FeignContext中获取Client,默认使用的是LoadBalancerFeignClient
Client client = getOptional(context, Client.class);
if (client != null) {
//client设置给builder
builder.client(client);
Targeter targeter = get(context, Targeter.class);
//targeter的target方法调用了Feign的target方法
//Feign的默认实现是ReflectiveFeign类,最终调用了ReflectiveFeign.newInstance方法创建实例
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
2.2.4 通过ReflectiveFeign创建Feign代理
public class ReflectiveFeign extends Feign {
...省略...
//target是HardCodedTarget,封装了客户端的type,name,url
public <T> T newInstance(Target<T> target) {
//得到Feign接口中的所有的方法MethodHandler
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
//把 Map<String, MethodHandler>变成Map<Method, MethodHandler>
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
Method[] var5 = target.type().getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method method = var5[var7];
if (method.getDeclaringClass() != Object.class) {
if (Util.isDefault(method)) {
//这里在添加默认的方法
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
}
InvocationHandler handler = this.factory.create(target, methodToHandler);
//生成代理
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
Iterator var12 = defaultMethodHandlers.iterator();
while(var12.hasNext()) {
//代理类绑定默认的方法
DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
defaultMethodHandler.bindTo(proxy);
}
//返回代理
return proxy;
}