@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/**注册@EnableFeignClients中定义defaultConfiguration属性下的类,包装成 FeignClientSpecification,
注册到Spring容器。在@FeignClient中有一个属性:configuration,这个属性是表示各个FeignClient
自定义的配置类,后面也会通过调用registerClientConfiguration方法来注册成FeignClientSpecification
到容器。所以,这里可以完全理解在@EnableFeignClients中配置的是做为兜底的配置,在各个@FeignClient
配置的就是自定义的情况。**/
this.registerDefaultConfiguration(metadata, registry);
/**将带有FeignClient的注解的接口注册到Spring容器中**/
this.registerFeignClients(metadata, registry);
}
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
scanner.setResourceLoader(this.resourceLoader);
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
//过滤出所有的带有FeignClient注解的类
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
Class[] clients = attrs == null?null:(Class[])((Class[])attrs.get("clients"));
Object basePackages;
if(clients != null && clients.length != 0) {
final HashSet clientClasses = new HashSet();
basePackages = new HashSet();
Class[] basePackage = clients;
int candidateComponents = clients.length;
for(int var11 = 0; var11 < candidateComponents; ++var11) {
Class candidateComponent = basePackage[var11];
((Set)basePackages).add(ClassUtils.getPackageName(candidateComponent));
clientClasses.add(candidateComponent.getCanonicalName());
}
AbstractClassTestingTypeFilter var18 = new AbstractClassTestingTypeFilter() {
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(new TypeFilter[]{var18, annotationTypeFilter})));
} else {
scanner.addIncludeFilter(annotationTypeFilter);
//获取EnableFeignClients设置的包扫描路径
basePackages = this.getBasePackages(metadata);
}
Iterator var17 = ((Set)basePackages).iterator();
while(var17.hasNext()) {
String var19 = (String)var17.next();
//扫描包路径下的所有类,并筛选出所有带有FeignClient注解的类,转化为BeanDefinition集合
Set var20 = scanner.findCandidateComponents(var19);
Iterator var21 = var20.iterator();
while(var21.hasNext()) {
BeanDefinition var22 = (BeanDefinition)var21.next();
if(var22 instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)var22;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
//获取FeignClient注解信息
Map attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = this.getClientName(attributes);
//以FeignClient注解配置的服务名称为BeanDefinition的名称前缀,注册FeignClientSpecification
this.registerClientConfiguration(registry, name, attributes.get("configuration"));
//将带有FeignClient注解的类设置代理,注册到Spring容器
this.registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
//FeignClientFactoryBean是一个FactoryBean,Spring容器实例化对象时会调用它的getObject方法。
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
this.validate(attributes);
definition.addPropertyValue("url", this.getUrl(attributes));
definition.addPropertyValue("path", this.getPath(attributes));
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
String contextId = this.getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
//definition的type设置为标注有FeignClient注解的实际接口名称
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(2);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute("factoryBeanObjectType", className);
boolean primary = ((Boolean)attributes.get("primary")).booleanValue();
beanDefinition.setPrimary(primary);
String qualifier = this.getQualifier(attributes);
if(StringUtils.hasText(qualifier)) {
alias = qualifier;
}
//BeanDefinitionHolder 的beanName设置为标注有FeignClient注解的实际接口名称
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
着重查看registerFeignClients方法,FeignClientsRegistrar.registerFeignClients 方法会扫描basePackages路径下所有的@FeignClient注解,再用扫描出来的类循环调用registerFeignClient方法,在FeignClientsRegistrar.registerFeignClient方法中,设置BeanDefinition的BeanClass为FeignClientFactoryBean,并将FeignClient注解的信息设置到BeanDefinition中,然后将这个BeanDefinition注册到Spring容器中。我们知道FeignClientFactoryBean是一个FactoryBean,Spring实例化BeanDefinition的时候会调用它的getObject方法。
public Object getObject() throws Exception {
return this.getTarget();
}
<T> T getTarget() {
//FeignContext是在FeignAutoConfiguration中初始化的
FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
//构建Builder对象
Builder builder = this.feign(context);
//如果FeignClient注解上没设置Url,走负载均衡,生成具有负载均衡功能的代理类
if(!StringUtils.hasText(this.url)) {
if(!this.name.startsWith("http")) {
this.url = "http://" + this.name;
} else {
this.url = this.name;
}
this.url = this.url + this.cleanPath();
return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url));
} else {
if(StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + this.cleanPath();
Client client = (Client)this.getOptional(context, Client.class);
if(client != null) {
if(client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient)client).getDelegate();
}
if(client instanceof FeignBlockingLoadBalancerClient) {
client = ((FeignBlockingLoadBalancerClient)client).getDelegate();
}
builder.client(client);
}
Targeter targeter = (Targeter)this.get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url));
}
}
protected Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = (FeignLoggerFactory)this.get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
//获取服务名称对应的Spring容器,并从容器中获取Builder、Encoder、Decoder、Contract等实例化对象
Builder builder = ((Builder)this.get(context, Builder.class)).logger(logger).encoder((Encoder)this.get(context, Encoder.class)).decoder((Decoder)this.get(context, Decoder.class)).contract((Contract)this.get(context, Contract.class));
this.configureFeign(context, builder);
return builder;
}
protected <T> T get(FeignContext context, Class<T> type) {
/**调用父类NamedContextFactory的getInstance,和Ribbon的SpringClientFactory的设计一样,通过
contextId(服务名称)来做容器的隔离,FeignContext向每个Spring容器注册了FeignClientsConfiguration配置类,
初始化了Decoder、Encoder、Contract等;但是每个容器初始化的FeignClientsConfiguration配置都是一样,没有
体现服务隔离的必要性,这里不是很理解**/
Object instance = context.getInstance(this.contextId, type);
if(instance == null) {
throw new IllegalStateException("No bean found of type " + type + " for " + this.contextId);
} else {
return instance;
}
}
public <T> T getInstance(String name, Class<T> type) {
AnnotationConfigApplicationContext context = this.getContext(name);
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0?context.getBean(type):null;
}
在FeignClientFactoryBean.getObject方法中,调用了FeignClientFactoryBean.getTarget方法,首先通过applicationContext获取FeignContext实例,然后调用FeignClientFactoryBean.feign方法,通过contextId(服务名称)从FeignContext中获取服务名称对应的Spring容器(如果没有对应服务名称的服务器,那么创建一个新的Spring容器,将原本的Spring容器作为这个新容器的父容器,向新容器中注册FeignClientsConfiguration类),并从Spring容器获取对应的Builder及Builder需要的各种成员变量。
protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) {
Client client = (Client)this.getOptional(context, Client.class);
if(client != null) {
builder.client(client);
Targeter targeter = (Targeter)this.get(context, Targeter.class);
return targeter.target(this, builder, context, target);
} else {
throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
}
构建好Builder后,如果url为空,调用FeignClientFactoryBean.loadBalance方法,生成具有负载均衡功能的代理类。其中targeter实例是在FeignAutoConfiguration中生成的,targeter.target()方法最终会调用Feign.target方法,在Feign的实现类ReflectiveFeign的newInstance方法中生成代理类,在ReflectiveFeign.newInstance方法中首先调用ParseHandlersByName.apply方法将FeignClient的所有方法都封装成MethodHandler(SynchronousMethodHandler,并以类名加方法名称为Key保存在Map结构中,类似于Spring的HandlerMethod设计,最后生成FeignInvocationHandler代理返回。
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
public <T> T newInstance(Target<T> target) {
//将所有FeignClient的接口解析封装成SynchronousMethodHandler
Map nameToHandler = this.targetToHandlersByName.apply(target);
LinkedHashMap methodToHandler = new LinkedHashMap();
LinkedList defaultMethodHandlers = new LinkedList();
Method[] handler = target.type().getMethods();
int proxy = handler.length;
for(int var7 = 0; var7 < proxy; ++var7) {
Method defaultMethodHandler = handler[var7];
if(defaultMethodHandler.getDeclaringClass() != Object.class) {
if(Util.isDefault(defaultMethodHandler)) {
DefaultMethodHandler handler1 = new DefaultMethodHandler(defaultMethodHandler);
defaultMethodHandlers.add(handler1);
methodToHandler.put(defaultMethodHandler, handler1);
} else {
methodToHandler.put(defaultMethodHandler, nameToHandler.get(Feign.configKey(target.type(), defaultMethodHandler)));
}
}
}
InvocationHandler var10 = this.factory.create(target, methodToHandler);
Object var11 = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, var10);
Iterator var12 = defaultMethodHandlers.iterator();
while(var12.hasNext()) {
DefaultMethodHandler var13 = (DefaultMethodHandler)var12.next();
var13.bindTo(var11);
}
return var11;
}
ParseHandlersByName.apply
public Map<String, MethodHandler> apply(Target target) {
//将FeignClient中的所有方法信息都封装到MethodMetadata中
List metadata = this.contract.parseAndValidateMetadata(target.type());
LinkedHashMap result = new LinkedHashMap();
Iterator var4 = metadata.iterator();
while(var4.hasNext()) {
MethodMetadata md = (MethodMetadata)var4.next();
Object buildTemplate;
if(!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target);
} else if(md.bodyIndex() != null) {//一般是post请求,但是参数没有注解是默认会放到body里面
buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target);
} else {//正常的get请求
buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, this.queryMapEncoder, target);
}
if(md.isIgnored()) {
result.put(md.configKey(), (args) -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
});
} else {
//以类名#方法名(参数类型)组成的字符串为key(具体查看Feign.configKey方法),将MethodMetadata封装到
SynchronousMethodHandler中。
result.put(md.configKey(), this.factory.create(target, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder));
}
}
return result;
}
BaseContract.parseAndValidateMetadata
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
LinkedHashMap result = new LinkedHashMap();
//获取接口所有的方法
Method[] var3 = targetType.getMethods();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
Method method = var3[var5];
if(method.getDeclaringClass() != Object.class && (method.getModifiers() & 8) == 0 && !Util.isDefault(method)) {
//对每个方法进行解析(包括注解信息),并保存到MethodMetadata中,如果存在接口方法上没有RequestMapping,会报错提示
MethodMetadata metadata = this.parseAndValidateMetadata(targetType, method);
result.put(metadata.configKey(), metadata);
}
}
return new ArrayList(result.values());
}
SpringMvcContract.parseAndValidateMetadata
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
this.processedMethods.put(Feign.configKey(targetType, method), method);
//将method的信息解析出来封装到MethodMetadata 中
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
RequestMapping classAnnotation = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(targetType, RequestMapping.class);
if(classAnnotation != null) {
//封装RequestMapping 配置的请求头信息
if(!md.template().headers().containsKey("Accept")) {
this.parseProduces(md, method, classAnnotation);
}
if(!md.template().headers().containsKey("Content-Type")) {
this.parseConsumes(md, method, classAnnotation);
}
this.parseHeaders(md, method, classAnnotation);
}
return md;
}
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
data.targetType(targetType);
data.method(method);
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
data.configKey(Feign.configKey(targetType, method));
if(targetType.getInterfaces().length == 1) {
this.processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
this.processAnnotationOnClass(data, targetType);
Annotation[] parameterTypes = method.getAnnotations();
int genericParameterTypes = parameterTypes.length;
for(int parameterAnnotations = 0; parameterAnnotations < genericParameterTypes; ++parameterAnnotations) {
Annotation count = parameterTypes[parameterAnnotations];
//解析方法注解中的信息,如RequestMapping
this.processAnnotationOnMethod(data, count, method);
}
if(data.isIgnored()) {
return data;
} else {
Class[] var10 = method.getParameterTypes();
Type[] var11 = method.getGenericParameterTypes();
Annotation[][] var12 = method.getParameterAnnotations();
int var13 = var12.length;
for(int i = 0; i < var13; ++i) {
boolean isHttpAnnotation = false;
if(var12[i] != null) {
//解析参数注解中的请求参数信息,如RequestParam
isHttpAnnotation = this.processAnnotationsOnParameter(data, var12[i], i);
}
if(isHttpAnnotation) {
data.ignoreParamater(i);
}
if(var10[i] == URI.class) {
data.urlIndex(Integer.valueOf(i));
} else if(!isHttpAnnotation && var10[i] != Options.class) {
//没有在方法参数上使用注解,默认将参数保存到body中,后续get请求转为post也是这
个原因导致的
if(!data.isAlreadyProcessed(Integer.valueOf(i))) {
data.bodyIndex(Integer.valueOf(i));
data.bodyType(Types.resolve(targetType, targetType, var11[i]));
} else {
}
}
}
if(data.headerMapIndex() != null) {
checkMapString("HeaderMap", var10[data.headerMapIndex().intValue()], var11[data.headerMapIndex().intValue()]);
}
if(data.queryMapIndex() != null && Map.class.isAssignableFrom(var10[data.queryMapIndex().intValue()])) {
checkMapKeys("QueryMap", var11[data.queryMapIndex().intValue()]);
}
return data;
}
}
protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
boolean isHttpAnnotation = false;
SpringMvcContract.SimpleAnnotatedParameterContext context = new SpringMvcContract.SimpleAnnotatedParameterContext(data, paramIndex);
Method method = (Method)this.processedMethods.get(data.configKey());
Annotation[] typeDescriptor = annotations;
int expander = annotations.length;
for(int var9 = 0; var9 < expander; ++var9) {
Annotation parameterAnnotation = typeDescriptor[var9];
//获取注解对应的处理器,如RequestParam默认使用RequestParamParameterProcessor
AnnotatedParameterProcessor processor =
(AnnotatedParameterProcessor)this.annotatedArgumentProcessors.get(parameterAnnotation.annotationType());
if(processor != null) {
Annotation processParameterAnnotation = this.synthesizeWithMethodParameterNameAsFallbackValue(parameterAnnotation, method, paramIndex);
//将请求参数保存到MethodMetadata的中,如RequestParam注解标注的参数会被保存到MethodMetadata的template的
queries变量中,get请求时将queries变量中的参数拼接到url上
isHttpAnnotation |= processor.processArgument(context, processParameterAnnotation, method);
}
}
if(!this.isMultipartFormData(data) && isHttpAnnotation && data.indexToExpander().get(Integer.valueOf(paramIndex)) == null) {
TypeDescriptor var13 = createTypeDescriptor(method, paramIndex);
if(this.conversionService.canConvert(var13, STRING_TYPE_DESCRIPTOR)) {
Expander var14 = this.convertingExpanderFactory.getExpander(var13);
if(var14 != null) {
data.indexToExpander().put(Integer.valueOf(paramIndex), var14);
}
}
}
return isHttpAnnotation;
}