原文:https://www.cnblogs.com/shamo89/p/8177182.html
(一)RestTemplate 客戶端
1、RestTemplate 是Spring的封裝,需要spring的包 spring-web-3.0.7.RELEASE.jar
2、客戶端代碼:
1 /** 2 * RestTemplate 客戶端訪問 3 */ 4 private void RestTemplateVisit() { 5 String returnXml = ""; // 核心返回結果報文字符串 6 7 try { 8 9 //復雜構造函數的使用 10 SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 11 requestFactory.setConnectTimeout(1000);// 設置超時 12 requestFactory.setReadTimeout(1000); 13 14 //利用復雜構造器可以實現超時設置,內部實際實現為 HttpClient 15 RestTemplate restTemplate = new RestTemplate(requestFactory); 16 17 //設置HTTP請求頭信息,實現編碼等 18 HttpHeaders requestHeaders = new HttpHeaders(); 19 // requestHeaders.set("Accept", "text/"); 20 requestHeaders.set("Accept-Charset", "utf-8"); 21 requestHeaders.set("Content-type", "text/xml; charset=utf-8");// 設置編碼 22 23 //利用容器實現數據封裝,發送 24 HttpEntity<String> entity = new HttpEntity<String>(mRequestXml, requestHeaders); 25 returnXml = restTemplate.postForObject(mUrl, entity, String.class); 26 27 // 轉碼原因:RestTemplate默認是使用org.springframework.http.converter.StringHttpMessageConverter來解析 28 // StringHttpMessageConverter 默認用的 ISO-8859-1來編碼的 29 returnXml = new String(returnXml.getBytes("ISO-8859-1"), "utf-8"); 30 31 } catch (UnsupportedEncodingException e) { 32 e.printStackTrace(); 33 } 34 35 System.out.println("restTemplate客戶端訪問返回: \n" + returnXml); 36 }
(二)RestTemplate 詳解
1、兩個構造方法:第二個實現超時。
public RestTemplate() { /** ...初始化過程 */ } //實現超時 public RestTemplate(ClientHttpRequestFactory requestFactory) { this(); setRequestFactory(requestFactory); }
其中,第二個構造方法中可以傳入ClientHttpRequestFactory參數,第一個進行默認初始化,因為我們經常需要對請求超時進行設置並能夠對超時進行后續處理,而第一個構造方法,我們無法控制超時時間,第二個構造中的ClientHttpRequestFactory接口的實現類中存在timeout屬性,因此選用第二個構造方法。
1 SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 2 requestFactory.setConnectTimeout(1000); 3 requestFactory.setReadTimeout(1000); 4 5 RestTemplate restTemplate = new RestTemplate(requestFactory);
Hystrix 超時配置的N種玩法
前陣子在我的知識星球中,有位朋友對我提了個問題,問我如何讓Hystrix支持對接口級別的超時配置,今天給大家寫篇文章,普及下Hystrix配置超時的幾種方式。
至於以后你是用阿里的Sentinel還是Netflix Hystrix我就不管了,但今天的主題還是Netflix Hystrix,至少目前還是有很多在使用的,所以今天這篇文章還是看看吧。
@HystrixCommand
如果我們使用的是@HystrixCommand注解,那么可以在注解中直接指定超時時間,如下:
@HystrixCommand(fallbackMethod="fallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000" ) } )
當然也可以指定commandKey,然后在配置文件中配置超時時間,如下:
@HystrixCommand(fallbackMethod="fallback",commandKey="userGetKey")
配置文件給commandKey配置超時時間:
hystrix.command.userGetKey.execution.isolation.thread.timeoutInMilliseconds = 13000
全局配置
如果只是想全局的配置,可以配置默認的超時時間:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
接口級別配置
假如我們的Feign Client定義如下:
@FeignClient(value = "user-service", fallbackFactory = UserRemoteClientFallbackFactory.class) public interface UserRemoteClient { @GetMapping("/user/get") public ResponseData<UserDto> getUser(@RequestParam("id") Long id); }
那么配置如下:
hystrix.command.UserRemoteClient#getUser(Long).execution.isolation.thread.timeoutInMilliseconds = 300
為什么要配置成上面的方式呢?
其實就是對commandKey進行配置,只要我們知道commandKey的生成規則就可以對接口級別進行配置,接口級別的規則是 Client名稱#方法名(參數類型)
源碼在feign.hystrix.SetterFactory.Default中:
String commandKey = Feign.configKey(target.type(), method);
服務級別配置
1.在Zuul中針對服務級別的話,直接配置service-id,如下:
hystrix.command.service-id.execution.isolation.thread.timeoutInMilliseconds=3000
Zuul中之所以要配置service-id原因是commandKey就是用的service-id, 通過源碼分析可以得到結論。
首先進入的是RibbonRoutingFilter中的run方法,然后我們看核心的forward方法:
ClientHttpResponse response = forward(commandContext);
在forward中有下面的代碼:
RibbonCommand command = this.ribbonCommandFactory.create(context);
通過create可以定位到具體的實現,這邊就看你用的什么Http客戶端,默認有三種實現,默認定位到org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommandFactory.create(RibbonCommandContext)方法。
重點在new HttpClientRibbonCommand這行代碼,第一個參數就是serviceId,我們看下HttpClientRibbonCommand構造函數的完整參數:
所以service-id就是commandKey。
2.在Feign中針對服務級別的話,需要對commandKey進行定制,可以用service-id, 也可以用Feign Client Name,如下:
@Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder().setterFactory(new SetterFactory() { @Override public Setter create(Target<?> target, Method method) { String groupKey = target.name(); String commandKey = Feign.configKey(target.type(), method); return HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey)) //.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey)) //.andCommandKey(HystrixCommandKey.Factory.asKey(groupKey)) .andCommandKey(HystrixCommandKey.Factory.asKey(target.type().getSimpleName())); } }); }
-
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
默認的接口方式 -
.andCommandKey(HystrixCommandKey.Factory.asKey(groupKey))
service-id方式 -
.andCommandKey(HystrixCommandKey.Factory.asKey(target.type().getSimpleName()));
Feign Client Name方式
配置的話根據不同的配置填寫不通的commandKey就可以了:
hystrix.command.Feign Client Name.execution.isolation.thread.timeoutInMilliseconds=3000