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 形式,不然会报错