springcloud的RestTemplate调用rest接口

springboot的RestTemplate调用rest接口

1.RestTemplate的三种使用方式

2.RestTemplate的加载问题

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

你可能感兴趣的:(springcloud微服务)