大体流程鱼骨图
1.读取配置
启动类上添加注解@EnableFeignClients,工程启动后会自动读取注解上的配置
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target(ElementType.TYPE) 3 @Documented 4 @Import(FeignClientsRegistrar.class) 5 public @interface EnableFeignClients { 6 。。。。。。属性省略 7 }
这里我们可以看到 EnableFeignClients 注解引入了配置类 org.springframework.cloud.openfeign.FeignClientsRegistrar
registerBeanDefinitions方法提供了注册 EnableFeignClients注解信息和 FeignClient信息的功能
1 @Override 2 public void registerBeanDefinitions(AnnotationMetadata metadata, 3 BeanDefinitionRegistry registry) { 4 registerDefaultConfiguration(metadata, registry); 5 registerFeignClients(metadata, registry); 6 }
拼接注解信息放在 definition中,然后交给spring容器管理
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClients
1 private void registerFeignClient(BeanDefinitionRegistry registry, 2 AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { 3 String className = annotationMetadata.getClassName(); 4 //根据工厂类获得对象 5 BeanDefinitionBuilder definition = BeanDefinitionBuilder 6 .genericBeanDefinition(FeignClientFactoryBean.class); 7 validate(attributes); 8 definition.addPropertyValue("url", getUrl(attributes)); 9 definition.addPropertyValue("path", getPath(attributes)); 10 String name = getName(attributes); 11 definition.addPropertyValue("name", name); 12 String contextId = getContextId(attributes); 13 definition.addPropertyValue("contextId", contextId); 14 definition.addPropertyValue("type", className); 15 definition.addPropertyValue("decode404", attributes.get("decode404")); 16 definition.addPropertyValue("fallback", attributes.get("fallback")); 17 definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); 18 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); 19 20 String alias = contextId + "FeignClient"; 21 AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); 22 23 boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be 24 // null 25 26 beanDefinition.setPrimary(primary); 27 28 String qualifier = getQualifier(attributes); 29 if (StringUtils.hasText(qualifier)) { 30 alias = qualifier; 31 } 32 33 BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, 34 new String[] { alias }); 35 BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); 36 }
2.创建代理实例方法
feign.ReflectiveFeign#newInstance
1 public <T> T newInstance(Target<T> target) { 2 Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target); 3 Map<Method, MethodHandler> methodToHandler = new LinkedHashMap(); 4 List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList(); 5 Method[] var5 = target.type().getMethods(); 6 int var6 = var5.length; 7 8 for(int var7 = 0; var7 < var6; ++var7) { 9 Method method = var5[var7]; 10 if (method.getDeclaringClass() != Object.class) { 11 if (Util.isDefault(method)) { 12 DefaultMethodHandler handler = new DefaultMethodHandler(method); 13 defaultMethodHandlers.add(handler); 14 methodToHandler.put(method, handler); 15 } else { 16 methodToHandler.put(method, (MethodHandler)nameToHandler.get(Feign.configKey(target.type(), method))); 17 } 18 } 19 } 20 //在这里我们可以看到feign创建了一个代理类 21 InvocationHandler handler = this.factory.create(target, methodToHandler); 22 T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler); 23 Iterator var12 = defaultMethodHandlers.iterator(); 24 25 while(var12.hasNext()) { 26 DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next(); 27 defaultMethodHandler.bindTo(proxy); 28 } 29 30 return proxy; 31 }
创建代理类的方法
1 public InvocationHandler create(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) { 2 return new FeignInvocationHandler(target, dispatch); 3 } 4 }
代理类的invoke方法,feign.ReflectiveFeign.FeignInvocationHandler#invoke
1 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 2 if (!"equals".equals(method.getName())) { 3 if ("hashCode".equals(method.getName())) { 4 return this.hashCode(); 5 } else { 6 return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args); 7 } 8 } else { 9 try { 10 Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; 11 return this.equals(otherHandler); 12 } catch (IllegalArgumentException var5) { 13 return false; 14 } 15 } 16 }
查看上面的invoke方法是怎么实现的
1 public interface MethodHandler { 2 Object invoke(Object[] var1) throws Throwable; 3 }
找到实现类 feign.SynchronousMethodHandler#invoke
1 public Object invoke(Object[] argv) throws Throwable { 2 //这里创建了一个template 3 RequestTemplate template = this.buildTemplateFromArgs.create(argv); 4 Options options = this.findOptions(argv); 5 Retryer retryer = this.retryer.clone(); 6 7 while(true) { 8 try { 9 10 return this.executeAndDecode(template, options); 11 } catch (RetryableException var9) { 12 RetryableException e = var9; 13 14 try { 15 retryer.continueOrPropagate(e); 16 } catch (RetryableException var8) { 17 Throwable cause = var8.getCause(); 18 if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) { 19 throw cause; 20 } 21 22 throw var8; 23 } 24 25 if (this.logLevel != Level.NONE) { 26 this.logger.logRetry(this.metadata.configKey(), this.logLevel); 27 } 28 } 29 } 30 }
然后调用ribbon,执行rest请求 org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute
1 @Override 2 public Response execute(Request request, Request.Options options) throws IOException { 3 try { 4 URI asUri = URI.create(request.url()); 5 String clientName = asUri.getHost(); 6 URI uriWithoutHost = cleanUrl(request.url(), clientName); 7 FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( 8 this.delegate, request, uriWithoutHost); 9 10 IClientConfig requestConfig = getClientConfig(options, clientName); 11 return lbClient(clientName) 12 .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); 13 } 14 catch (ClientException e) { 15 IOException io = findIOException(e); 16 if (io != null) { 17 throw io; 18 } 19 throw new RuntimeException(e); 20 } 21 }
-----------------------------------------------------------------------------------------------------------------------------
大部分都是贴的源码,本文只是为了记录一次feign的大致实现思想,其中很多精妙的方式并没有提及