Feign请求过程的处理

本文解析了FeignClient在Spring容器中的实现原理,详细介绍了FeignInvocationHandler如何通过SynchronousMethodHandler处理方法调用,生成RequestTemplate并发起HTTP请求的过程。
摘要由CSDN通过智能技术生成

FeignClient接口在Spring容器中都是生成关联FeignInvocationHandler的代理类,所以在调用FeignClient接口的方法时,都会执行FeignInvocationHandler.invoke方法,FeignClient的接口方法的信息都被解析封装在SynchronousMethodHandler中,并以FeignClient接口的Method为key,SynchronousMethodHandler为value,保存在dispatch变量的Map结构中。在FeignInvocationHandler.invoke方法中,会通过调用的Method,从dispatch中找到对应的SynchronousMethodHandler,并执行SynchronousMethodHandler的invoke方法。

FeignInvocationHandler.invoke:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if(!"equals".equals(method.getName())) {
      //通过method从Map集合中获取对应的SynchronousMethodHandler
        return "hashCode".equals(method.getName())?Integer.valueOf(this.hashCode()):("toString".equals(method.getName())?this.toString():((MethodHandler)this.dispatch.get(method)).invoke(args));
   
    } else {
        try {
            InvocationHandler e = args.length > 0 && args[0] != null?Proxy.getInvocationHandler(args[0]):null;
            return Boolean.valueOf(this.equals(e));
        } catch (IllegalArgumentException var5) {
            return Boolean.valueOf(false);
        }
    }
}

SynchronousMethodHandler.invoke:

public Object invoke(Object[] argv) throws Throwable {
    //根据请求参数生成RequestTemplate对象
    RequestTemplate template = this.buildTemplateFromArgs.create(argv);
    Options options = this.findOptions(argv);
    Retryer retryer = this.retryer.clone();
    while(true) {
        try {
            return this.executeAndDecode(template, options);
        } catch (RetryableException var9) {
            RetryableException e = var9;
            try {
                retryer.continueOrPropagate(e);
            } catch (RetryableException var8) {
                Throwable cause = var8.getCause();
                if(this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
                    throw cause;
                }
                throw var8;
            }
            if(this.logLevel != Level.NONE) {
                this.logger.logRetry(this.metadata.configKey(), this.logLevel);
            }
        }
    }
}

 在SynchronousMethodHandler.invoke方法中会调用BuildTemplateByResolvingArgs.create方法解析请求参数,生成RequestTemplate。BuildTemplateByResolvingArgs.create中,从MethodMetadata中复制出一个新的RequestTemplate,然后调用BuildEncodedTemplateFromArgs.resolve(body有数据使用BuildEncodedTemplateFromArgs.resolve{BuildTemplateByResolvingArgs的子类}方法封装完请求的body后也会调用父类BuildTemplateByResolvingArgs.resolve方法)方法进行参数的解析。

BuildTemplateByResolvingArgs.create: 

public RequestTemplate create(Object[] argv) {
    RequestTemplate mutable = RequestTemplate.from(this.metadata.template());
    mutable.feignTarget(this.target);
    if(this.metadata.urlIndex() != null) {
        int varBuilder = this.metadata.urlIndex().intValue();
        Util.checkArgument(argv[varBuilder] != null, "URI parameter %s was null", new Object[]{Integer.valueOf(varBuilder)});
        mutable.target(String.valueOf(argv[varBuilder]));
    }
    LinkedHashMap varBuilder1 = new LinkedHashMap();
    Iterator template = this.metadata.indexToName().entrySet().iterator();
    while(true) {
        Entry value;
        int queryMap;
        Object value1;
        do {
            if(!template.hasNext()) {
                //解析参数
                RequestTemplate template1 = this.resolve(argv, mutable, varBuilder1);
                if(this.metadata.queryMapIndex() != null) {//方法参数有@SpringQueryMap注解会走这个逻辑
                    Object value2 = argv[this.metadata.queryMapIndex().intValue()];
                    Map queryMap1 = this.toQueryMap(value2);
                    //将标注有@SpringQueryMap的参数的字段名称和值添加到RequestTemplate的 
                 queries属性中,后续会调用RequestTemplate.url方法将参数拼接到url上面
                    template1 = this.addQueryMapQueryParameters(queryMap1, template1);
                }
                if(this.metadata.headerMapIndex() != null) {
                    template1 = this.addHeaderMapHeaders((Map)argv[this.metadata.headerMapIndex().intValue()], template1);
                }
                return template1;
            }
            value = (Entry)template.next();
            queryMap = ((Integer)value.getKey()).intValue();
            value1 = argv[((Integer)value.getKey()).intValue()];
        } while(value1 == null);
        if(this.indexToExpander.containsKey(Integer.valueOf(queryMap))) {
            value1 = this.expandElements((Expander)this.indexToExpander.get(Integer.valueOf(queryMap)), value1);
        }
        Iterator var8 = ((Collection)value.getValue()).iterator();
        while(var8.hasNext()) {
            String name = (String)var8.next();
            varBuilder1.put(name, value1);
        }
    }
}

BuildEncodedTemplateFromArgs.resolve: 

protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map<String, Object> variables) {
    Object body = argv[this.metadata.bodyIndex().intValue()];
    Util.checkArgument(body != null, "Body parameter %s was null", new Object[]{this.metadata.bodyIndex()});

    try {
        //封装请求中Body的参数
        this.encoder.encode(body, this.metadata.bodyType(), mutable);
    } catch (EncodeException var6) {
        throw var6;
    } catch (RuntimeException var7) {
        throw new EncodeException(var7.getMessage(), var7);
    }
    //调用父类的BuildTemplateByResolvingArgs的resolve方法
    return super.resolve(argv, mutable, variables);
}
BuildTemplateByResolvingArgs.resolve方法最终会调用RequestTemplate.resolve进行参数的处理:

protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map<String, Object> variables) {
    return mutable.resolve(variables);
}

 RequestTemplate.resolve:

public RequestTemplate resolve(Map<String, ?> variables) {
    StringBuilder uri = new StringBuilder();
    RequestTemplate resolved = from(this);
    if(this.uriTemplate == null) {
        this.uriTemplate = UriTemplate.create("", !this.decodeSlash, this.charset);
    }
    String expanded = this.uriTemplate.expand(variables);
    if(expanded != null) {
        uri.append(expanded);
    }
    String headerValues;
    String header1;
    if(!this.queries.isEmpty()) {
        //上次说过@RequestParam标注的参数信息会被设置到queries中保存,这里会根据参数名称从请求中获取参数的值,
而且这里会将queries设置为空,因为后面调用RequestTemplate.url方法时,
会再次将queries的参数拼接到url上,不请空会导致重复

        resolved.queries(Collections.emptyMap());
        StringBuilder query = new StringBuilder();
        Iterator headerTemplate = this.queries.values().iterator();
        while(headerTemplate.hasNext()) {
            QueryTemplate header = (QueryTemplate)headerTemplate.next();
            headerValues = header.expand(variables);
            if(Util.isNotBlank(headerValues)) {
                //将请求参数拼接到url上
                query.append(headerValues);
                if(headerTemplate.hasNext()) {
                    query.append("&");
                }
            }
        }
        header1 = query.toString();
        if(!header1.isEmpty()) {
            Matcher headerValues1 = QUERY_STRING_PATTERN.matcher(uri);
            if(headerValues1.find()) {
                uri.append("&");
            } else {
                uri.append("?");
            }
            uri.append(header1);
        }
    }
    resolved.uri(uri.toString());
    if(!this.headers.isEmpty()) {
        resolved.headers(Collections.emptyMap());
        Iterator query1 = this.headers.values().iterator();
        while(query1.hasNext()) {
            HeaderTemplate headerTemplate1 = (HeaderTemplate)query1.next();
            header1 = headerTemplate1.expand(variables);
            if(!header1.isEmpty()) {
                headerValues = header1.substring(header1.indexOf(" ") + 1);
                if(!headerValues.isEmpty()) {
                    resolved.header(headerTemplate1.getName(), new TemplateChunk[]{Literal.create(headerValues)});
                }
            }
        }
    }
    if(this.bodyTemplate != null) {
        resolved.body(this.bodyTemplate.expand(variables));
    }
    resolved.resolved = true;
    return resolved;
}
回到SynchronousMethodHandler.invoke方法,调用buildTemplateFromArgs.create方法,解析请求参数,生成了RequestTemplate 之后,调用SynchronousMethodHandler.executeAndDecode方法,发起http请求。
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    //调用Feign拦截器,组装request,设置请求的url,参数等
    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 {
        //调用LoadBalancerFeignClient的execute方法,比如Ribbon的请求调用逻辑
        response = this.client.execute(request, options);
        response = response.toBuilder().request(request).requestTemplate(template).build();
    } catch (IOException var12) {
        if(this.logLevel != Level.NONE) {
            this.logger.logIOException(this.metadata.configKey(), this.logLevel, var12, this.elapsedTime(start));
        }

        throw FeignException.errorExecuting(request, var12);
    }

    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
    if(this.decoder != null) {
        return this.decoder.decode(response, this.metadata.returnType());
    } else {
        CompletableFuture resultFuture = new CompletableFuture();
        this.asyncResponseHandler.handleResponse(resultFuture, this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);

        try {
            if(!resultFuture.isDone()) {
                throw new IllegalStateException("Response handling not done");
            } else {
                return resultFuture.join();
            }
        } catch (CompletionException var13) {
            Throwable cause = var13.getCause();
            if(cause != null) {
                throw cause;
            } else {
                throw var13;
            }
        }
    }
}
Request targetRequest(RequestTemplate template) {
    //获取设置的所有的Feign拦截器
    Iterator var2 = this.requestInterceptors.iterator();

    while(var2.hasNext()) {//迭代调用
        RequestInterceptor interceptor = (RequestInterceptor)var2.next();
        interceptor.apply(template);
    }
    //组装request,设置请求的url,参数等
    return this.target.apply(template);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值