源码分析
(1)EnableFeignClients注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import({FeignClientsRegistrar.class}) public @interface EnableFeignClients { //略 }
(2)FeignClientsRegistrar注册类
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { this.registerDefaultConfiguration(metadata, registry); this.registerFeignClients(metadata, registry); } }
通过其类结构可知,由于实现了ImportBeanDe?nitionRegistrar接口,那么在registerBeanDe?nitions()中就会解析和注册BeanDe?nition,主要注册的对象类型有两种:
注册缺省配置的配置信息
注册那些添加了@FeignClient的类或接口 : 这也是我们讨论的重点
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = this.getScanner(); scanner.setResourceLoader(this.resourceLoader); Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName()); 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 Set<String> clientClasses = new HashSet(); basePackages = new HashSet(); Class[] var9 = clients; int var10 = clients.length; for(int var11 = 0; var11 < var10; ++var11) { Class<?> clazz = var9[var11]; ((Set)basePackages).add(ClassUtils.getPackageName(clazz)); clientClasses.add(clazz.getCanonicalName()); } AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() { protected boolean match(ClassMetadata metadata) { String cleaned = metadata.getClassName().replaceAll("\\$", "."); return clientClasses.contains(cleaned); } }; scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter))); } else { scanner.addIncludeFilter(annotationTypeFilter); basePackages = this.getBasePackages(metadata); } Iterator var17 = ((Set)basePackages).iterator(); while(var17.hasNext()) { String basePackage = (String)var17.next(); Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage); Iterator var21 = candidateComponents.iterator(); while(var21.hasNext()) { BeanDefinition candidateComponent = (BeanDefinition)var21.next(); if (candidateComponent instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName()) ; String name = this.getClientName(attributes); this.registerClientConfiguration(registry, name, attributes.get("configuration")); this.registerFeignClient(registry, annotationMetadata, attributes); } } } }
该方法主要是扫描类路径,对所有的FeignClient生成对应的 BeanDefinitio 。同时又调用了registerClientConfiguration 注册配置的方法,这里是第二处调用。这里主要是将扫描的目录下,每个项目的配置类加载的容器当中。调用 registerFeignClient 注册对象
(3) 注册FeignClient对象
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { // 1.获取类名称,也就是本例中的FeignService接口 String className = annotationMetadata.getClassName(); // 2.BeanDefinitionBuilder的主要作用就是构建一个AbstractBeanDefinition // AbstractBeanDefinition类最终被构建成一个BeanDefinitionHolder // 然后注册到Spring中 // 注意:beanDefinition类为FeignClientFactoryBean,故在Spring获取类的时候实际返回 的是 // FeignClientFactoryBean类 BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); // 3.添加FeignClientFactoryBean的属性, // 这些属性也都是我们在@FeignClient中定义的属性 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); // 4.设置别名 name就是我们在@FeignClient中定义的name属性 String alias = name + "FeignClient"; 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; } // 5.定义BeanDefinitionHolder, // 在本例中 名称为FeignService,类为FeignClientFactoryBean BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
通过分析可知:我们最终是向Spring中注册了一个bean,bean的名称就是类或接口的名称(也就是本例中的FeignService),bean的实现类是FeignClientFactoryBean,其属性设置就是我们在@FeignClient中定义的属性。那么下面我们在Controller中对FeignService的的引入,实际就是引入了FeignClientFactoryBean 类
(4) FeignClientFactoryBean类
我们对@EnableFeignClients注解的源码进行了分析,了解到其主要作用就是把带有@FeignClient注解的类或接口用FeignClientFactoryBean类注册到Spring中。
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { public Object getObject() throws Exception { return this.getTarget(); } //略 }
通过 FeignClientFactoryBean 类结构可以发现其实现了FactoryBean类,那么当从ApplicationContext中获取该bean的时候,实际调用的是其getObject()方法。返回调用getTarget()方法
<T> T getTarget() { FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class); Builder builder = this.feign(context); 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(); } builder.client(client); } Targeter targeter = (Targeter)this.get(context, Targeter.class); return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url)); } }
FeignClientFactoryBean实现了FactoryBean的getObject、getObjectType、isSingleton方法;
实现了InitializingBean的afterPropertiesSet方法;实现了ApplicationContextAware的setApplicationContext方法
getObject调用的是getTarget方法,它从applicationContext取出FeignContext,然后构造Feign.Builder并设置了logger、encoder、decoder、contract,之后通过con?gureFeign根据FeignClientProperties来进一步配置Feign.Builder的retryer、errorDecoder、request.Options、requestInterceptors、queryMapEncoder、decode404
初步配置完Feign.Builder之后再判断是否需要loadBalance,如果需要则通过loadBalance方法来设置,不需要则在Client是LoadBalancerFeignClient的时候进行unwrap
(5) 发送请求
由上可知,FeignClientFactoryBean.getObject()具体返回的是一个代理类,具体为FeignInvocationHandler
static class FeignInvocationHandler implements InvocationHandler { private final Target target; private final Map<Method, MethodHandler> dispatch; FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) { this.target = (Target)Util.checkNotNull(target, "target", new Object[0]); this.dispatch = (Map)Util.checkNotNull(dispatch, "dispatch for %s", new Object[]{target}); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!"equals".equals(method.getName())) { if ("hashCode".equals(method.getName())) { return this.hashCode(); } else { return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args); } } else { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return this.equals(otherHandler); } catch (IllegalArgumentException var5) { return false; } } } public boolean equals(Object obj) { if (obj instanceof ReflectiveFeign.FeignInvocationHandler) { ReflectiveFeign.FeignInvocationHandler other = (ReflectiveFeign.FeignInvocationHandler)obj; return this.target.equals(other.target); } else { return false; } } public int hashCode() { return this.target.hashCode(); } public String toString() { return this.target.toString(); } }
FeignInvocationHandler实现了InvocationHandler,是动态代理的代理类。
当执行非Object方法时进入到this.dispatch.get(method)).invoke(args)
dispatch是一个map集合,根据方法名称获取MethodHandler。具体实现类为SynchronousMethodHandler
final class SynchronousMethodHandler implements MethodHandler { public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = this.buildTemplateFromArgs.create(argv); Retryer retryer = this.retryer.clone(); while(true) { try { return this.executeAndDecode(template); } catch (RetryableException var8) { //略 } } } Object executeAndDecode(RequestTemplate template) throws Throwable { Request request = this.targetRequest(template); if (this.logLevel != Level.NONE) { this.logger.logRequest(this.metadata.configKey(), this.logLevel, request); } long start = System.nanoTime(); Response response; try { response = this.client.execute(request, this.options); } catch (IOException var15) { //略 } } }
SynchronousMethodHandler内部创建了一个RequestTemplate对象,是Feign中的请求模板对象。内部封装了一次请求的所有元数据。
retryer中定义了用户的重试策略。
调用executeAndDecode方法通过client完成请求处理,client的实现类是LoadBalancerFeignClient