RestTemplate是Spring提供的用于发送HTTP请求的客户端工具,它遵循Restful原则,RestTemplate默认依赖JDK的Http连接工具HttpUrlConnection,你也可以替换不同的源,比如OkHttp、Apache HttpComponents 等等。。
Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务。
而OpenFeign则是可以让我们像调用Dubbo接口一样,实现面向接口编程
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequestMapping等等。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,
并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
微服务需要对服务进行拆分,服务拆分之后,就涉及服务的通信,通信的话可以使用RestTemplate,一个服务可能放在多台机器上,有多个副本,这个时候就需要做负载均衡,可用将Robbin与RestTemplate集成后实现负载均衡,所以在RestTemplate真正发起HTTP请求之前做了一个拦截,这个拦截就是LoadBalancerInterceptor完成的,它的最终实现是RibbonLoadBlancerClient去进行拦截和处理,在拦截过程中分析了几个阶段,第一个阶段是初始化阶段,怎么对加了LoadBalancer的注解RestTemplate进行拦截,通过讲解了自动装配过程,讲到LoadBalancerAutoConfiguration自动装配类,这个装配类里边是嵌套的Bean的依赖,下图的顺序就是bean的初始化的过程。通过这个一个过程对RestTemplate加了一个拦截,就可以使用负载均衡处理。
Robbin的调用流程分为四个部分:
1,初始化阶段,通过自动装配将RestTemplate与LoadBalancerInterceptor绑定到一起;
初始化的时候会自动加载LoadBalancerAutoConfiguration类,会将加了@LoadBalance注解的RestTemplate通过 @LoadBalancer和@AutoWired注入到List restTemplates; LoadBalancerInterceptor也会自动被注入,使用其中SmartInitializingSingleton组装bean,对于所有的RestTemplate 调用RestTemplateCustomizer将拦截器加到RestTemplate 实例中
2,获取负载均衡器,通过负载均衡器中配置的默认算法选择一个合适的Server;
通过 RestTemplate .getForObject()发起请求,一定会进入到拦截器中LoadBalancerInterceptor会调用intercept(),接着会调用LoadBalancerClient接口的实现类RibbonLoadBalancerClient.execute();其中就引出两个比较重要的方法,分别是 getLoadBalancer()获取负载均衡器和Server getServer()通过负载均衡器配置的默认算法选择合适server;
IloadBalance 接口,有几个比较重要的实现类,分别是ZoneAwareLoadBalancer、DynamicServerListLoadBalancer、BaseLoadBalancer,通常用作默认的负载均衡器,其DynamicServerListLoadBalancer用来更新服务器的列表,BaseLoadBalancer配置Iping的策略和Rule规则,Rule默认为轮询策略,Iping默认不开启,开启的话默认10s检查一次服务列表是否运行;默认情况下getLoadBalancer会使用工厂模式根据serverID获取IloadBalance 接口实例ZoneAwareLoadBalancer,ZoneAwareLoadBalancer会调用父类DynamicServerListLoadBalancer构造方法restOfInit,其中有两个重要的方法 enableAndInitLearnNewServersFeature()和updateListOfServers();
enableAndInitLearnNewServersFeature方法的作用是使用schedule开启定时任务每30s执行updateListOfServers方法更新服务列表;
接着执行updateListOfServers更新服务器列表的方法,updateListOfServers会调用serverListImpl.getUpdatedListOfServers();
-------getUpdatedListOfServers有两种实现方式,一种是从本地配置获取服务器列表基于ConfigurationBasedServerList实现,另一种是从Eureka注册中心上动态获取服务列表基于DiscoveryEnabledNIWSServerList实现,使用eurekaClient获取服务实例列表。
--------获取到更新列表之后,调用DynamicServerListLoadBalancer.updateAllServerList();最终通过一系列的链路调用,使用BaseLoadBalancer.setServerList方法对allServerList和upServerList完成列表的更新。
3,解析URL,将服务名请求路径转转为Ip+端口的请求形式
接着调用
RibbonLoadBalancerClient.execute()方法,其一系列的链路调用,最终RibbonLoadBalancerClient.ReconstructURI方法重构URL;
接着使用AsyncClientHttpRequestExecution.execte()发起异步远程调用。
OpenFigen调用过程
OpenFeign的调用过程:
可以沿着两条路线进行分析,一是分析@EnableFeignClients,@FeignClient;
首先从**@EnableFeignClients()**注解进入@Import({FeignClientsRegistrar.class});
FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar接口;动态的将Bean装载到IOC容器中;
FeignClientsRegistrar类调用registerFeignClients();对于配置的package中可以能有多个FeignClient,用双重循环遍历不同路径下的不同的FeignClients和配置;
接着进入registerFeignClient()方法中;FeignClient被动态注册成一个FactoryBean,FactoryBean有一个特征,就是如果需要获得这个Bean的真正实例,会通过**FeignClientFactoryBean.getObject()**中getTarget来获取最终实例,getTarget中会根据是否有URL,如果没有执行LoadBalancer负载均衡,否则进入下一个流程。
接着是构建动态动态代理对象
当我们通过@Autowired XXXXFeignClient的时候,会通过FeignClientFactoryBean.getTarget()获取目标对象,接着调用HystrixTargeter.target(),接着调用Feign.target();ReflectiveFeign.newInstance()
接着是解析接口类的注释声明
调用ReflectiveFeign.apply(),通过SpringMvcContarct.parseAndValidateMetadata将接口类的注释声明解析为MethodMetadata,MethodHandler,并且将以方法名为键,MethodHandler为值,将其存储到Map<String, MethodHandler> result
下面从HTTP网络通信的角度来分析,
前台发起HTTP请求,会受到动态代理的拦截,通过FeignInvocationHandler.invoke(),它会调用 this.dispatch.get(method)).invoke(args)
接着调用SynchronousMethodHandler.invoke()方法会进入到Feign.create方法,其使用之前解析出来的MethodMetadata构建RequestTemplate对象,接着Encode编码,将Bean包装成Request请求,发起HTTP通信进行调用,发起请求之前LoadBalancerFeignClient做负载均衡,可以通过logger进行日志记录,接着重试机制,如果发送失败,重新发送,接着发起HTTP请求;接着Response回应,反序列化。