Feign源码,feignclient源码解析
目录
假装接口动态代理源码解析@FeignClinet代理类注册假装源码解析假装的作用源码及流程介绍
feign接口动态代理源码解析
@FeignClinet 代理类注册
@FeignClinet通过动态代理实现的底层超文本传送协议(超文本传输协议的缩写)调用,既然是动态代理,必然存在创建代理类的过程。如Proxy.newProxyInstance或者cgliborg。spring框架。云。打开假装的代理类注册实现如下。
首先,组织。spring框架。云。打开假装。feignclientsregistrar注册FeignClientFactoryBean到一个缓存中.一个接口对应FeignClientFactoryBean。
弹簧初始化容器过程中执行
org。spring框架。云。打开假装。feignclientfactorybean。getObject()@覆盖公共对象getObject()抛出异常{ return get target();}/* * * * @ param T Feign客户端的目标类型* @返回用指定数据和上下文信息创建的{@link Feign}客户端*/T T get target(){ Feign context context=应用程序上下文。getbean(假装上下文。类);假装Builder builder=feign(上下文);如果(!字符串实用程序。hastext(这个。URL)){ if(!这个。姓名。以( http ){ URL= http:// this。姓名;} else { URL=this . name } URL=clean path();return (T) loadBalance(builder,context,new HardCodedTarget(this.type,this.name,URL));} if(字符串utils。hastext(这个。网址)!这个。网址。以( http ){ this。URL= http://这。网址;}字符串URL=this。URL清理路径();client client=get可选(上下文,客户端。类);如果(客户端!=null){ if(LoadBalancerFeignClient的客户端实例){//不负载平衡因为我们有url,//但是带状物在类路径上,所以unwrap client=((LoadBalancerFeignClient)client).get delegate();} builder.client(客户端);} Targeter targeter=get(上下文,Targeter。类);return (T) targeter.target(this,builder,context,new HardCodedTarget(this.type,this.name,URL));}其中getObject()实现了接口的getObject(),
作用是在春天语境初始化时创建豆实例,如果伊辛莱顿()返回没错,则该实例会放到弹簧容器的
单实例缓存池中。
然后是targeter.target() 如果启用了Hystrix调用的就是
org.springframework.cloud.openfeign.HystrixTargeter.target()
org.springframework.cloud.openfeign.HystrixTargeter
/*** @param factory bean工厂* @param feign feign对象的构造类* @param context feign接口上下文,* @param target 保存了feign接口的name,url和FeignClient的Class对象***/@Override public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } Class<?> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(factory.getName(), context, target, builder, fallback); } Class<?> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory); } return feign.target(target); }
再看下去 feign.target(target)
feign.Feign.Builder
public <T> T target(Target<T> target) { return build().newInstance(target); } public Feign build() { SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
build() 返回一个ReflectiveFeign对象。
往下看,ReflectiveFeign的newInstance方法。
feign.ReflectiveFeign
@Override public <T> T newInstance(Target<T> target) { //关键方法: 解析target对象,返回key 为 feign接口的url ,value 为请求执行类:SynchronousMethodHandler Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>(); List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { continue; } else if (Util.isDefault(method)) { DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } //创建代理类 handler ,返回对象 feign.ReflectiveFeign.FeignInvocationHandler InvocationHandler handler = factory.create(target, methodToHandler); T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler); for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { defaultMethodHandler.bindTo(proxy); } return proxy; }
至此,代理类注册完成。
当调用feign接口时,其实执行的是 feign.ReflectiveFeign.FeignInvocationHandler的invoke 方法
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("equals".equals(method.getName())) { try { Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; return equals(otherHandler); } catch (IllegalArgumentException e) { return false; } } else if ("hashCode".equals(method.getName())) { return hashCode(); } else if ("toString".equals(method.getName())) { return toString(); } //dispatch.get(method)返回的是 SynchronousMethodHandler 对象 return dispatch.get(method).invoke(args); }
调用的 SynchronousMethodHandler invoke 方法。
feign.SynchronousMethodHandler
@Override public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = buildTemplateFromArgs.create(argv); Retryer retryer = this.retryer.clone(); while (true) { try { return executeAndDecode(template); } catch (RetryableException e) { try { retryer.continueOrPropagate(e); } catch (RetryableException th) { Throwable cause = th.getCause(); if (propagationPolicy == UNWRAP && cause != null) { throw cause; } else { throw th; } } if (logLevel != Logger.Level.NONE) { logger.logRetry(metadata.configKey(), logLevel); } continue; } } }
executeAndDecode 方法执行RPC调用的逻辑。
小结一下:FeignClientsRegistrar解析@FeignClient注解,注册对应的FeignClientFactoryBean–》通过FeignClientFactoryBean的getObject()方法返回代理对象 feign.ReflectiveFeign.FeignInvocationHandler
feign源码解析
首先我要说的是springcloud没有rpc,这就涉及rpc和微服务的区别。springcloud的模块通信工具feign跟httpclient和okhttp是一样的东西,都是对http请求封装的工具,其实feign可以选择httpclient或者okhttp作为底层实现(修改配置即可)。
Feign的作用
①封装http请求,使开发人员对发送请求的过程无感知,给人一种伪rpc感觉(这也许是feign这个名字的由来吧,伪装~)。
②feign整合ribbon和hystrix,结合eureka起到负载均衡和熔断器、降级作用。
源码及流程介绍
我们从@EnableFeignClients这个注解开始追踪
我们发现有个@Import注解,引用FeignClientRegistrar类,跟进去看看
2个方法:①redisterDefalterConfiguration是加载配置,②registerFeignClients扫描你填写的basepackage下的所有@FeignClient注解的接口。第一个方法没啥好说的,我们主要看看第二个方法。
扫描完之后,把所有包含@FeignClient注解的接口都注册到spring的beanfactory去,让开发人员可以@Autowired来调用。这一部分代码我就不贴了,我们只是追求feign的原理流程,太涉及spring源码部分,我不做解释。
=========== 以上是feign注册流程,下面介绍拼装request请求部分 ===========
首先,这里看ReflectiveFeign类,这个类用的是jdk的动态代理
用到代理模式肯定是在发送feign请求之前做一些操作,继续看看请求之前做了哪些操作。
代理拦截每一个FeignClient请求,进入SynchronousMethodHandler的invoke方法,该方法调用executeAndDecode方法,这个方法看名字就知道是创建请求的方法,进去看看。
在该方法发送请求并且解码,解码分为decoder和errordecoder,这两个都是可以重写。这里你可能会问解码器,那编码器呢,feign默认用springEncoder,同样是可以替换成Gson等。
=========== 以上是feign的调用流程,以下是feign使用过程的坑===========
①feign在D版本后默认关闭hystrix,要想传递请求头,如果不用hystrix的话在feign拦截器里塞一遍就好;如果要用hystrix,那么改用信号量。
②在C版本后默认关闭hystrix,要使用要手动开启
③不要妄想改变feign的逻辑,因为代理模式被写成final,无法修改
④无法在解码器里抛自定义异常,因为feign最终会统一拦截,抛出一个feignexception。你想把统一拦截也改了,那么你可以看看第③坑。
⑤feign的重试机制,默认是1,也就是说超时时间会变成2倍。这个可以通过配置修改。
⑥feign集成的负载均衡器ribbon,feign有个缓存,ribbon也有个缓存,会造成上线延迟,可以修改配置实现。
⑦feign对格式化时间处理有问题
⑧如果你是使用生产者提供api,并且实现该接口,@requestparam可以不用在实现类写,但是@requestbody不写无法映射
以上的坑都是我在实际工作中一个一个爬过来的,仅为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。