1.RestTemplate的三种使用方式
ServerController
@RestController
public class ServerController {
@GetMapping("/msg")
public String msg(){
return "this is product msg";
}
}
ClientController
@RestController
@Slf4j
public class ClientController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getProductMsg")
public String msg(){
//1.第一种方式(直接使用restTemplate,url写死)
// RestTemplate restTemplate = new RestTemplate();
// String response = restTemplate.getForObject("http://localhost:8888/msg", String.class);
//2.弟二种方式(利用loadBalancerClient通过应用名获取url,然后再使用直接使用restTemplate)
// ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
// String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort())+"/msg";
// RestTemplate restTemplate = new RestTemplate();
// String response = restTemplate.getForObject(url, String.class);
//
//3.弟二种方式(利用@LoadBalanced,可在restTemplate里使用应用名字)
String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
log.info("response={}",response);
return response;
}
}
第三种方式需要先定义一个bean
//这里就是创建一个负载均衡的RestTemplate Bean
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
2.RestTemplate的加载问题
当我们需要在项目启动时就去用restTemplate是存在一个加载先后问题,
在第三种方式时 ,先看看@LoadBalanced注解
/**
* Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
* @author Spencer Gibb
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
这就是一个普通的标记注解,作用就是修饰RestTemplate让其拥有负载均衡的能力,查看org.springframework.cloud.client.loadbalancer包下面的class,我们很容易发现LoadBalancerAutoConfiguration这个类;
@Configuration //这是一个配置类
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class) //这个配置文件加载必要条件是存在RestTemplate类和LoadBalancerClient
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//这个很重要,这里的restTemplates是所有的被@LoadBalanced注解的集合,
// 这就是标记注解的作用(Autowired是可以集合注入的)
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
//生成一个LoadBalancerInterceptor的Bean
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
//给注解了@LoadBalanced的RestTemplate加上拦截器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
/**
* Auto configuration for retry mechanism.
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
}
/**
* Auto configuration for retry intercepting mechanism.
*/
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryInterceptorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRetryProperties properties,
LoadBalancerRequestFactory requestFactory,
LoadBalancedRetryFactory loadBalancedRetryFactory) {
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
requestFactory, loadBalancedRetryFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
在其中
//这个很重要,这里的restTemplates是所有的被@LoadBalanced注解的集合,
// 这就是标记注解的作用(Autowired是可以集合注入的)
@LoadBalanced
@Autowired(required = false)
private List restTemplates = Collections.emptyList();
@Autowired(required = false)
private List transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
我们可以看到被@LoadBalanced注解标记的RestTemplate被加入到RestTemplateCustomizer 中
如果我们想在项目启动时不会因为加载问题导致出错,我们可以在定义RestTemplate的bean时就将RestTemplate加入到RestTemplateCustomizer 中,这样也就不存在加载问题,因为可能各种原因restTemplate在运行方法是如果还没有注册到注册中心,查找服务时肯定失败
@Bean
public RestTemplate loadBalancedRestTemplate(RestTemplateCustomizer customizer) {
RestTemplate restTemplate = new RestTemplate();
customizer.customize(restTemplate);
return restTemplate;
}
定义时就引入RestTemplateCustomizer ,不需要实现他,因为在LoadBalancerAutoConfiguration中已经定义了bean