zoukankan      html  css  js  c++  java
  • spring cloud openfeign源码分析

    大体流程鱼骨图

     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的大致实现思想,其中很多精妙的方式并没有提及

  • 相关阅读:
    增强资源管理器右键功能,含源代码
    VC中结构体的内存布局
    进程间共享句柄三种方式
    Delphi获取CPU CPUID《转》
    Delphi中判断WebBrowser的页面是否加载完成 《转》
    Delphi 防止程序多次运行《转》
    界面显示后延时运行代码《转》
    界面显示后延时运行代码《转》
    DIV布局-DIV高度不同自动换行并对齐《转》
    Delphi 语句块《LceMeaning》
  • 原文地址:https://www.cnblogs.com/yechen2019/p/11661226.html
Copyright © 2011-2022 走看看