restTemplate 是spring 提供的http请求工具,类似于httpclient,
默认情况下与其他的http 工具类没有区别
但是当添加了@Loadbalance 注解之后,则具备了负载均衡功能,可以通过服务名找到对应的ip:port进行访问
闲话少说,我们直接上demo
注册templete loadbalance bean
如果引入了spring cloud 默认会注册 loadbalance resttemplate
@Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); }
使用方式 post 使用demo案例
我这里是用的spring cloud nacos ,针对工作流回调函数传入服务名进行负载均衡调用
@Autowired private RestTemplate restTemplate; /*** * * @param serverName 服务名 * @param event 回调事件 * @param vars 回调参数j'son * @return R<String> 返回结果 * */ @Override public R<String> call(String serverName,String event, String vars) { log.info("serverName:{},event:{},vars:{}",serverName,event,vars); String url = "http://"+serverName+"/workflow/callback/event"; HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(SecurityConstants.FROM, SecurityConstants.FROM_IN); HttpEntity<Void> httpEntity = new HttpEntity<>(null, httpHeaders); MultiValueMap<String, String> requestMap = new LinkedMultiValueMap<>(); requestMap.add("event", event); requestMap.add("dataMapString", vars); ResponseEntity<R> r = restTemplate.exchange(url, HttpMethod.POST,httpEntity,R.class,requestMap); return R.ok(); }
接收端
/** * 工作流回调接口 * * @param event 事件名称 * @param dataMapString 传递参数 * dataMapString 参数如下: * flag :审批结果 "审批,驳回,终止" * username: 该流程提交者用户名 * busi_id: startSubmit 返回的流程业务id,与业务挂钩的主键 * nodeId: 节点Id * assignee: 分配的审批人 * auditer: 真正完成审批人 * comment: 审批意见 */ @Inner @RequestMapping("/event") @ApiOperation(value = "工作流各种回调事件接口", tags = "工作流各种回调事件接口") public R callBack(String event,String dataMapString) { System.out.println("event:" + event + ",dataMapString:" + dataMapString); //流程相关参数 Map<String, String> params = JSON.parseObject(dataMapString, new TypeReference<Map<String, String>>() { }); //流程节点分到了具体审批人后回调事件 if (WorkflowCallBackEvent.EVENT_ASSIGNEE.equals(event)) { return R.ok(); }else{ return R.failed(); } }
redistemplete 执行loadbanlace 运行流程与源码分析
为了大家方便理解,我画了一个简单的运行泳道图,主要分为两个部分,第一是启动部分,如下图:
启动部分源码分析
整体流程描述
1. 通过LoadBalancerAutoConfiguration 加载所有带有@LoadBalanced 注解的restTemplate
2. 初始化 执行 loadBalancedRestTemplateInitializerDeprecated 方法内部遍历执行 customizer.customize(restTemplate)
3. customizer.customize(restTemplate) 其实就是执行 之前注入的bean RestTemplateCustomizer,然后执行restTemplate.setInterceptors(list)
初始化完毕
详细步骤源码分析
1. 通过LoadBalancerAutoConfiguration 加载所有带有@LoadBalanced 注解的restTemplate
重点,为什么是加载了有@LoadBalanced 注解的restTemplate 而不是所有的restTemplate ,因为@LoadBalanced 内有一个@Qualifier 元注解
因此有@LoadBalanced 注解的restTemplate 就绑成了一个整体注入到了spring 中管理
2. 初始化 执行 loadBalancedRestTemplateInitializerDeprecated 方法内部遍历执行 customizer.customize(restTemplate)
3. customizer.customize(restTemplate) 其实就是执行 之前注入的bean RestTemplateCustomizer,然后执行restTemplate.setInterceptors(list);
setInterceptors(list) 其实就是注入了RetryLoadBalancerInterceptor ,现在完成后也就是将含有loadbalance 注解的resttemplate 注入了interceptor
redistemplete 执行exchange 负载均衡源码分析(参照上面流程图)
整体流程描述
1. redistemplete 执行 exchange,然后内部 exchange->execute->doExecute
2. 然后 createRequest 然后通过 getRequestFactory 创建request
3. getRequestFactory 会根据是否内部注册了拦截器来返回不同的factory, 有拦截会返回InterceptingClientHttpRequestFactory ,没有会返回SimpleClientHttpRequestFactory
4. InterceptingClientHttpRequestFactory 会创建返回InterceptingClientHttpRequest,SimpleClientHttpRequestFactory 会创建返回SimpleBufferingAsyncClientHttpRequest
5. SimpleBufferingAsyncClientHttpRequest 会正常和httpclient 一样执行execute,暂不多说,主要来说InterceptingClientHttpRequest ,这个是负责负载均衡的
6. InterceptingClientHttpRequest 执行execute ,内部会先执行拦截器也就是之前启动注入的RetryLoadBalancerInterceptor
7. RetryLoadBalancerInterceptor 内部会执行 RibbonLoadBalancerClient 的choose 方法用NamedContextFactory 将服务名从注册中心获取实例转为ip:port 的ServiceInstance
8. 然后 RetryLoadBalancerInterceptor 会拿着得到的ServiceInstance 正常执行http请求得到 ClientHttpResponse
9. 返回response 全部流程结束
详细步骤源码分析
1. redistemplete 执行 exchange,然后内部 exchange->execute->doExecute
2. 然后 createRequest 然后通过 getRequestFactory 创建request
3. getRequestFactory 会根据是否内部注册了拦截器来返回不同的factory, 有拦截会返回InterceptingClientHttpRequestFactory ,没有会返回SimpleClientHttpRequestFactory
4. InterceptingClientHttpRequestFactory 会创建返回InterceptingClientHttpRequest,SimpleClientHttpRequestFactory 会创建返回SimpleBufferingAsyncClientHttpRequest
5. SimpleBufferingAsyncClientHttpRequest 会正常和httpclient 一样执行execute,暂不多说,主要来说InterceptingClientHttpRequest ,这个是负责负载均衡的
6. InterceptingClientHttpRequest 执行execute ,内部会先执行拦截器也就是之前启动注入的RetryLoadBalancerInterceptor
7. RetryLoadBalancerInterceptor 内部会执行 RibbonLoadBalancerClient 的choose 方法用 NamedContextFactory 将服务名从注册中心获取实例转为ip:port 的ServiceInstance
8. 然后 RetryLoadBalancerInterceptor 会拿着得到的ServiceInstance 正常执行http请求得到 ClientHttpResponse
9. 返回response 全部流程结束
注意点:如果resttemplate 加了@loadbalance 注解,那么就不可以在用ip:port 形式的url请求了,只能用servername 形式,不然会报错