[享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler...

面试中会问,笔试中会考,工作中要用的知识点如果你不掌握,那么面试一般都是到此一游,定级自己为API调用工程师即可。

–> 返回专栏总目录 <–
代码下载地址:https://github.com/f641385712/feign-learning

前言

本文接着上篇文章,接着介绍Feign的核心API部分。革命尚未统一,同志仍需努力。


正文

Logger

feign.Logger是Feign自己抽象出来的一个日志记录器,定位为调试用的简单日志抽象。

public abstract class Logger {
	
  // 记录日志时,对configKey进行格式化  子类可以复写这种实现,但一般都没必要	
  protected static String methodTag(String configKey) {
    return new StringBuilder().append('[').append(configKey.substring(0, configKey.indexOf('(')))
        .append("] ").toString();
  }
	
	// 它是个protected的抽象方法,子类必须复写。三大参数交给你,子类决定如何书写(写控制台or写文件?)
	// 比如你可以使用System.out,可以用Log4j、SLF4j都可以...
	protected abstract void log(String configKey, String format, Object... args);

	// 记录请求信息。你可以复写,但一般没必要。保持出厂格式吧...
	protected void logRequest(String configKey, Level logLevel, Request request) {
		// 打印请求URL...
		log(configKey, "---> %s %s HTTP/1.1", request.httpMethod().name(), request.url());
		
		// 接下来的内容,只有日志级别在HEADERS以及以上才输出
		// 这是Feign自己的日志级别:NONE,BASIC,HEADERS,FULL
		// 所以只有日志级别为HEADERS,FULL下面才会输出,日志级别是你定的。但默认是NONE
		if (logLevel.ordinal() >= Level.HEADERS.ordinal()) {
			... // 除数请求头、请求体、响应码、响应体等
		}
	}

	// 记录响应信息
	protected Response logAndRebufferResponse(...) { ... }
	// 记录异常信息
	protected IOException logIOException(...){ ... }
}

综上可以看到,其实留给子类实现的抽象方法有且仅有一个:log()方法。Feign自己内置了三个实现类:

  • ErrorLogger:极其简单,仅实现了log()方法,使用错误流System.err.printf(methodTag(configKey) + format + "%n", args)直接删除
  • NoOpLogger:实现了相关方法,全部为空实现。这是Feign默认的日志记录器
  • JavaLogger:基于JDK自己的java.util.logging.Logger logger去记录日志,但是,但是,但是JDK自己的日志级别必须在FINE以上才会进行记录,而它默认的级别是INFO,所以FINE、DEBUG等都不会输出
    • 你若想JDK的这个日志器输出,你得通过配置文件等放置改变对应实例的日志级别,相对麻烦,生产环境其实一般不用它,后面会讲和SLF4j的集成。

InvocationHandlerFactory

控制反射方法调度。它是一个工厂,用于为目标target创建一个java.lang.reflect.InvocationHandler反射调用对象。

public interface InvocationHandlerFactory {
	
	// Dispatcher:每个方法对应的MethodHandler -> SynchronousMethodHandler实例
	// 创建出来的是一个FeignInvocationHandler实例,实现了InvocationHandler接口
	InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
}

Default

它有且仅有一个实现类:feign.InvocationHandlerFactory.Default

static final class Default implements InvocationHandlerFactory {

	// 很简单:调用FeignInvocationHandler构造器完成实例的创建
    @Override
    public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
      return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
  }

创建InvocationHandler的实例很简单,直接调用FeignInvocationHandler的构造器完成。但是很有必要细读它的invoke方法,它是对方法完成正调度的核心,是所有方法调用的入口


FeignInvocationHandler

它实现了InvocationHandler接口,用于调度所有的Method。

static class FeignInvocationHandler implements InvocationHandler {

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;
	...

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      ... //省略对equals、hashCode、toString等方法的处理代码
	
	  // 通过dispath完成调度,因此最终调用的是MethodHandler#invoke
      return dispatch.get(method).invoke(args);
    }
}

可以看到该invoke方法仅仅是调度了一下而已,最终实际是委托给SynchronousMethodHandler#invoke(args)去完成实际的调用:发送http请求 or 调用接口本地方法。

说明:SynchronousMethodHandler是整个Feign核心流程的重中之重,我把它放在文末着重讲解分析


Contract

这个接口非常重要:它决定了哪些注解可以标注在接口/接口方法上是有效的,并且提取出有效的信息,组装成为MethodMetadata元信息

public interface Contract {

	// 此方法来解析类中链接到HTTP请求的方法:提取有效信息到元信息存储
	// MethodMetadata:方法各种元信息,包括但不限于
	// 返回值类型returnType
	// 请求参数、请求参数的index、名称
	// url、查询参数、请求body体等等等等
	List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}

该接口的继承结构如下图:

在这里插入图片描述


BaseContract

抽象基类。

abstract class BaseContract implements Contract {
    @Override
    public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
		// 这些检查挺有意思的
		// 1、类上不能存在任何一个泛型变量
		... targetType.getTypeParameters().length == 0
		// 2、接口最多最多只能有一个父接口
		... targetType.getInterfaces().length <= 1
			targetType.getInterfaces()[0].getInterfaces().length == 0

		// 对该类所有的方法进行解析:包装成一个MethodMetadata
		// getMethods表示本类 + 父类的public方法
		// 因为是接口,所有肯定都是public的(当然Java8支持private、default、static等)
		Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
		for (Method method : targetType.getMethods()) {
			... // 排除掉Object的方法、static方法、default方法等
			
			// parseAndValidateMetadata是本类的一个protected方法
			MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
			// 请注意这个key是:metadata.configKey()
			result.put(metadata.configKey(), metadata);

			// 注意:这里并没有把result直接返回回去
			// 而是返回一个快照版本
			return new ArrayList<>(result.values());
		}
    }
}

从此处可以清楚的看到,Feign虽然基于接口实现,但它对接口是有要求的

  1. 不能是泛型接口
  2. 接口最多只能有一个父接口(当然可以没有父接口)

然后他会处理所有的接口方法,包含父接口的。但不包含接口里的默认方法、私有方法、静态方法等,也排除掉Object里的方法。
而对方法的到元数据的解析,落在了parseAndValidateMetadata()这个protected方法上:

BaseContract:

	protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
		MethodMetadata data = new MethodMetadata();
		// 方法返回类型是支持泛型的
		data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
		// 这里使用了Feign的一个工具方法,来生成configKey,不用过于了解细节,简单的说就是尽量唯一
		data.configKey(Feign.configKey(targetType, method));

	  // 这一步很重要:处理接口上的注解。并且处理了父接口哦
	  // 这就是为何你父接口上的注解,子接口里也生效的原因哦~~~
	  // processAnnotationOnClass()是个abstract方法,交给子类去实现(毕竟注解是可以扩展的嘛)
      if (targetType.getInterfaces().length == 1) {
        processAnnotationOnClass(data, targetType.getInterfaces()[0]);
      }
      processAnnotationOnClass(data, targetType);
	
	  // 处理标注在方法上的所有注解
	  // 若子接口override了父接口的方法,注解请以子接口的为主,忽略父接口方法
      for (Annotation methodAnnotation : method.getAnnotations()) {
        processAnnotationOnMethod(data, methodAnnotation, method);
      }
		// 简单的说:处理完方法上的注解后,必须已经知道到底是GET or POST 或者其它了
	   checkState(data.template().method() != null,


		// 方法参数,支持泛型类型的。如List<String>这种...
      Class<?>[] parameterTypes = method.getParameterTypes();
      Type[] genericParameterTypes = method.getGenericParameterTypes();

	   // 注解是个二维数组...
      Annotation[][] parameterAnnotations = method.getParameterAnnotations();
      int count = parameterAnnotations.length;
      // 一个注解一个注解的处理
      for (int i = 0; i < count; i++) {
		...
		// processAnnotationsOnParameter是抽象方法,子类去决定
        if (parameterAnnotations[i] != null) {
          isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
        }

		// 方法参数若存在URI类型的参数,那url就以它为准,并不使用全局的了
		if (parameterTypes[i] == URI.class) {
			data.urlIndex(i);
		}
		... 
		// 校验body:
		// 1、body参数不能用作form表单的parameters
		// 2、Body parameters不能太多
		
		...
		return data;
      }
		
	}

按照从上至下流程解析每一个方法上的注解信息,抽象方法留给子类具体实现:

  • processAnnotationOnClass:
  • processAnnotationOnMethod:
  • processAnnotationsOnParameter:

这三个抽象方法非常的公用,决定了识别哪些注解、解析哪些注解,因此特别适合第三方扩展。
显然,Feign内置的默认实现实现了这些接口,就连Spring MVC的扩展SpringMvcContract也是通过继承它来实现支持@RequestMapping等注解的。


Default

它是BaseContract的内置唯一实现类,也是Feign的默认实现

class Default extends BaseContract {

	static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$");

	// 支持注解:@Headers
    @Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> targetType) { ... }

	// 支出注解:@RequestLine、@Body、@Headers
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) { ... }

	// 支持注解:@Param、@QueryMap、@HeaderMap等
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { ... }
	...
}

通过这个子类实现,可以很清楚的看到Feign原生支持哪些注解类型,它和上篇文章的介绍是完全吻合的。


MethodHandler

功能上类似于java.lang.reflect.InvocationHandler#invoke()方法,接口定义非常简单:

interface MethodHandler {
	Object invoke(Object[] argv) throws Throwable;
}

接口定义虽简单,但它是完成Feign发送请求过程的重中之重。该接口有两个内置实现类:
在这里插入图片描述
注意:该接口名字叫MethodHandler,而JDK的叫MethodHandle,不要弄混了…


DefaultMethodHandler

它是通过调用接口默认方法(因为它并不持有Target这种代理对象,所以接口中能用的方法只能是默认方法喽)代码来处理方法,注意:bindTo方法必须在invoke方法之前调用。

它依赖的技术是Java7提供的方法句柄MethodHandle,比反射来得更加的高效,缺点是编码稍显复杂。

说明:关于JDK的方法句柄MethodHandle具体如何使用?有兴趣的同学请自行研究

// 访问权限是Default
final class DefaultMethodHandler implements MethodHandler {

	private final MethodHandle unboundHandle;
	private MethodHandle handle;

	// 从Method里拿到方法句柄,赋值给unboundHandle
	public DefaultMethodHandler(Method defaultMethod) { ... }


  // 把目标对象(代理对象)绑定到方法句柄上
  // 这样unboundHandle就变为了已经绑定好的handle,这样invoke就能调用啦
  public void bindTo(Object proxy) {
    if (handle != null) {
      throw new IllegalStateException("Attempted to rebind a default method handler that was already bound");
    }
    handle = unboundHandle.bindTo(proxy);
  }

  // 调用目标方法
  // 调用前:请确保已经绑定了目标对象
  @Override
  public Object invoke(Object[] argv) throws Throwable {
    if (handle == null) {
      throw new IllegalStateException("Default method handler invoked before proxy has been bound.");
    }
    return handle.invokeWithArguments(argv);
  }
}

默认实现的特点是:采用的方法句柄MethodHandle的方式去“反射”执行目标方法,很显然它只能执行到接口默认方法,所以一般木有远程通信这么一说。


SynchronousMethodHandler(重中之重)

同步方法调用处理器,它强调的是同步二字,且有远程通信。

final class SynchronousMethodHandler implements MethodHandler {
	
	// 方法元信息
	private final MethodMetadata metadata;
	// 目标  也就是最终真正构建Http请求Request的实例 一般为HardCodedTarget
	private final Target<?> target;
	// 负责最终请求的发送 -> 默认传进来的是基于JDK源生的,效率很低,不建议直接使用
	private final Client client;
	// 负责重试 -->默认传进来的是Default,是有重试机制的哦,生产上使用请务必注意
	private final Retryer retryer;

	// 请求拦截器,它会在target.apply(template); 也就是模版 -> 请求的转换之前完成拦截
	// 说明:并不是发送请求之前那一刻哦,请务必注意啦
	// 它的作用只能是对请求模版做定制,而不能再对Request做定制了
	// 内置仅有一个实现:BasicAuthRequestInterceptor 用于鉴权
	private final List<RequestInterceptor> requestInterceptors;

	// 若你想在控制台看到feign的请求日志,改变此日志级别为info吧(因为一般只有info才会输出到日志文件)
	private final Logger.Level logLevel;
	...
	// 构建请求模版的工厂
	// 对于请求模版,有多种构建方式,内部会用到可能多个编码器,下文详解
	private final RequestTemplate.Factory buildTemplateFromArgs;
	// 请求参数:比如链接超时时间、请求超时时间等
	private final Options options;

	// 解码器:用于对Response进行解码
	private final Decoder decoder;
	// 发生错误/异常时的解码器
	private final ErrorDecoder errorDecoder;

	// 是否解码404状态码?默认是不解码的
	private final boolean decode404;
	
	// 唯一的构造器,并且还是私有的(所以肯定只能在本类内构建出它的实例喽)
	// 完成了对如上所有属性的赋值
	private SynchronousMethodHandler( ... ) { ... }

  	@Override
  	public Object invoke(Object[] argv) throws Throwable {
  		// 根据方法入参,结合工厂构建出一个请求模版
		RequestTemplate template = buildTemplateFromArgs.create(argv);
		// findOptions():如果你方法入参里含有Options类型这里会被找出来
		// 说明:若有多个只会有第一个生效(不会报错)
		Options options = findOptions(argv);
		// 重试机制:注意这里是克隆一个来使用
		Retryer retryer = this.retryer.clone();
		while (true) {
		     try {
		        return executeAndDecode(template, options);
		      } catch (RetryableException e) {
				
				// 若抛出异常,那就触发重试逻辑
		       try {
		       	  // 该逻辑是:如果不重试了,该异常会继续抛出
		       	  // 若要充值,就会走下面的continue
		          retryer.continueOrPropagate(e);
		        } catch (RetryableException th) {
		        	...
		        }
		        continue;
		      }
		}
  	}
}

MethodHandler实现相对复杂,用一句话描述便是:准备好所有参数后,发送Http请求,并且解析结果。它的步骤我尝试总结如下:

  1. 通过方法参数,使用工厂构建出一个RequestTemplate请求模版
    1. 这里会解析@RequestLine/@Param等等注解
  2. 从方法参数里拿到请求选项:Options(当然参数里可能也没有此类型,那就是null喽。如果是null,那最终执行默认的选项)
  3. executeAndDecode(template, options)执行发送Http请求,并且完成结果解码(包括正确状态码的解码和错误解码)。这个步骤比较复杂,拆分为如下子步骤:
    1. 把请求模版转换为请求对象feign.Request
      1. 执行所有的拦截器RequestInterceptor,完成对请求模版的定制
      2. 调用目标target,把请求模版转为Request:target.apply(template);
    2. 发送Http请求:client.execute(request, options),得到一个Response对象(这里若发生IO异常,也会被包装为RetryableException重新抛出)
    3. 解析此Response对象,解析后return(返回Object:可能是Response实例,也可能是decode解码后的任意类型)。大致会有如下情况:
      1. Response.class == metadata.returnType(),也就是说你的方法返回值用的就是Response。若response.body() == null,也就是说服务端是返回null/void的话,就直接return response;若response.body().length() == null,就直接返回response;否则,就正常返回response.toBuilder().body(bodyData).build() body里面的内容吧
      2. 200 <= 响应码 <= 300,表示正确的返回。那就对返回值解码即可:decoder.decode(response, metadata.returnType())(解码过程中有可能异常,也会被包装成FeignException向上抛出)
      3. 若响应码是404,并且decode404 = true,那同上也同样执行decode动作
      4. 其它情况(4xx或者5xx的响应码),均执行错误编码:errorDecoder.decode(metadata.configKey(), response)
  4. 发送http请求若一切安好,那就结束了。否则执行重试逻辑:
    1. 通过retryer.continueOrPropagate(e);看看收到此异常后是否要执行重试机制
    2. 需要重试的话就continue(注意上面是while(true)哦~)
    3. 若不需要重试(或者重试次数已到),那就重新抛出此异常,向上抛出
    4. 处理此异常,打印日志…

我个人认为,这是Feign作为一个HC最为核心的逻辑,请各位读者务必掌握


总结

关于Feign的核心API部分就介绍到这里,虽然枯燥但和知识点很硬核,只要啃下来必能有所获。
虽然核心API不可能100%全部讲到,但大部分均已cover,对后续的学习几无障碍,欢迎一起来造…
分隔线

声明

原创不易,码字不易,多谢你的点赞、收藏、关注。把本文分享到你的朋友圈是被允许的,但拒绝抄袭。你也可【左边扫码/或加wx:fsx641385712】邀请你加入我的 Java高工、架构师 系列群大家庭学习和交流。
往期精选

发布了377 篇原创文章 · 获赞 572 · 访问量 51万+
展开阅读全文

Spring clouud eureka feign调用问题

11-03

最近在学习使用spring cloud 的时候遇到这样一个问题,项目划分了3个模块 注册中心、服务提供方、服务消费方. 分别启动3个项目后 在注册中心的web管理页面 能看到服务提供方和服务消费方都已经注册上来了。但是 当服务消费方调用方法时,通过日志看到是以服务提供方的别名为IP地址发起调用的 一调用就报错 请各位大神们帮忙看看 最好能给我讲讲为什么会出现这个问题 注册中心启动类 ```/** * 注册中心启动类 * */ @EnableEurekaServer @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } ``` 注册中心配置 ``` server.port=8001 #自我注册 eureka.client.register-with-eureka=false eureka.client.fetch-registry=false # eureka.server.enable-self-preservation=true eureka.server.eviction-interval-timer-in-ms=60000 #关闭自我保护 eureka.server.enableSelfPreservation=false eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/ ``` 服务提供方启动类 ``` @EnableDiscoveryClient @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } ``` 服务提供方Rest接口 ```@RestController @RequestMapping("menu") public class BMenuController { @Autowired private IBMenuService menuService; private static final Logger logger = LoggerFactory.getLogger(BMenuController.class); @RequestMapping("/selectById/{id}") public BMenu selectById(@PathVariable("id") Integer id) { logger.info("数据访问层 菜单通过ID获取 调用 id:[{}]", id); return menuService.selectById(id); } ``` 服务提供方配置: ```#设置应用的名称 spring.application.name=ic-generic #服务注册的Eureka Server地址 #eureka.client.serviceUrl.defaultZone=http://hlwic:hlwic@localhost:8001/eureka eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka server.port=8002 ``` 服务消费方启动类: ```@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } ``` 服务消费方 feign接口: ``` @FeignClient("ic-generic") public interface IBMenuService { @RequestMapping("/menu/selectById/{id}") public BMenu selectById(@PathVariable("id") Integer id); ``` 服务消费方配置: ``` spring.application.name=ic-app server.port=8005 eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/ ``` ![图片说明](https://img-ask.csdn.net/upload/201711/03/1509679661_1124.png) 异常信息: ```2017-11-03 11:25:13.827 INFO 12140 --- [nio-8005-exec-4] com.hlw.ic.app.facade.BMenuController : 控制器接收到app端发起的通过id查询菜单请求 params[{"id":1}] 2017-11-03 11:25:22.483 WARN 12140 --- [nio-8005-exec-4] com.hlw.ic.app.facade.BMenuController : app端发起的通过id查询菜单请求 发生异常 params[{"id":1}] feign.RetryableException: connect timed out executing GET http://ic-generic/menu/selectById/1 at feign.FeignException.errorExecuting(FeignException.java:67) ~[feign-core-9.5.0.jar:na] at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:104) ~[feign-core-9.5.0.jar:na] at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.5.0.jar:na] at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.0.jar:na] at com.sun.proxy.$Proxy82.selectById(Unknown Source) ~[na:na] at com.hlw.ic.app.facade.BMenuController.queryById(BMenuController.java:74) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.9.RELEASE.jar:4.3.9.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) [spring-boot-actuator-1.5.4.RELEASE.jar:1.5.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.15.jar:8.5.15] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.15.jar:8.5.15] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.15.jar:8.5.15] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131] Caused by: java.net.SocketTimeoutException: connect timed out at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:1.8.0_131] at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) ~[na:1.8.0_131] at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_131] at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_131] at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_131] at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_131] at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_131] at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_131] at sun.net.NetworkClient.doConnect(NetworkClient.java:175) ~[na:1.8.0_131] at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_131] at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_131] at sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:1.8.0_131] at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_131] at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1202) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1138) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1032) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:966) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546) ~[na:1.8.0_131] at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474) ~[na:1.8.0_131] at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) ~[na:1.8.0_131] at feign.Client$Default.convertResponse(Client.java:152) ~[feign-core-9.5.0.jar:na] at feign.Client$Default.execute(Client.java:74) ~[feign-core-9.5.0.jar:na] at org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:80) ~[spring-cloud-netflix-core-1.3.1.RELEASE.jar:1.3.1.RELEASE] at org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:48) ~[spring-cloud-netflix-core-1.3.1.RELEASE.jar:1.3.1.RELEASE] at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:109) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) ~[rxjava-1.1.10.jar:1.1.10] at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) ~[rxjava-1.1.10.jar:1.1.10] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.1.10.jar:1.1.10] at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.1.10.jar:1.1.10] at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10] at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10] at rx.Observable.subscribe(Observable.java:10307) ~[rxjava-1.1.10.jar:1.1.10] at rx.Observable.subscribe(Observable.java:10274) ~[rxjava-1.1.10.jar:1.1.10] at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445) ~[rxjava-1.1.10.jar:1.1.10] at rx.observables.BlockingObservable.single(BlockingObservable.java:342) ~[rxjava-1.1.10.jar:1.1.10] at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:117) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2] at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) ~[spring-cloud-netflix-core-1.3.1.RELEASE.jar:1.3.1.RELEASE] at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ~[feign-core-9.5.0.jar:na] ... 70 common frames omitted 2017-11-03 11:25:22.724 INFO 12140 --- [nio-8005-exec-4] com.hlw.ic.app.facade.BMenuController : 控制器接收到app端发起的通过id查询菜单请求 处理完成 耗时[8760] params[{"id":1}] 响应信息[{"code":-1,"mess":"异常"}] ``` 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie

分享到微信朋友圈

×

扫一扫,手机浏览