RestTemplate负载均衡
调用代码
@RestController
public class UserController {
@Autowired
RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
//方式一
// @Bean
// //@LoadBalanced 开启客户端负载均衡,即restTemplate.getForObject 必须通过服务名称访问
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
//方式二
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
return restTemplateBuilder.build();
}
@GetMapping("/user/orders")
public String getUserOrders(){
String returnStr="";
ServiceInstance serviceInstance=loadBalancerClient.choose("xue-service-order");
String requestUrl=String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort()+"/orders");
System.out.println(requestUrl);
returnStr+=restTemplate.getForObject(requestUrl,String.class);
return returnStr;
}
}
调用方配置
server.port=8088
spring.application.name=xue-service-user
xue-service-order.ribbon.listOfServers=127.0.0.1:8086,127.0.0.1:8087
@LoadBalanced 负载均衡
调用代码
@RestController
public class UserController2 {
@Autowired
RestTemplate restTemplate;
//方式一
//开启客户端负载均衡,即restTemplate.getForObject 必须通过服务名称访问
// @Bean
// @LoadBalanced
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
//方式二
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
return restTemplateBuilder.build();
}
@GetMapping("/user/orders2")
public String getUserOrders(){
String returnStr="";
String requestUrl="http://xue-service-order/orders";
System.out.println(requestUrl);
returnStr+=restTemplate.getForObject(requestUrl,String.class);
return returnStr;
}
}
@LoadBalanced原理
注解内容分析,
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
@Qualifier 注解起到的作用
public class TestClass {
private String name;
public TestClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Configuration
public class TestConfiguration {
@Bean("testClass1")
TestClass testClass(){
return new TestClass("testClass1");
}
@Qualifier
@Bean("testClass2")
TestClass testClass2(){
return new TestClass("testClass2");
}
}
@RestController
public class TestController {
@Autowired
@Qualifier
List<TestClass> testClassList= Collections.emptyList();
@GetMapping("/test")
public Object getTest() {
return testClassList;
}
}
接口返回结果, [{“name”:“testClass2”}],说明@Qualifier 注解标记的bean 会被自动扫描到,并装配到@Qualifier 标记的 List testClassList 中,
所以 @LoadBalanced也有同样的作用
@LoadBalanced如何进行负载均衡的
入口 LoadBalancerAutoConfiguration 自动装配类
主要将拦截器加入到restTemplates
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RestTemplate.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
//和我们案例中的下段代码作用一致,获得所有标记了,@LoadBalanced的RestTemplate的bean
//@Autowired
//@Qualifier
//List<TestClass> testClassList= Collections.emptyList();
@LoadBalanced
@Autowired(
required = false
)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(
required = false
)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
public LoadBalancerAutoConfiguration() {
}
//下面都是利用@Bean 去装配,最终将拦截器装配到restTemplates 中(restTemplate.setInterceptors(list);)
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> {
restTemplateCustomizers.ifAvailable((customizers) -> {
Iterator var2 = this.restTemplates.iterator();
while(var2.hasNext()) {
RestTemplate restTemplate = (RestTemplate)var2.next();
Iterator var4 = customizers.iterator();
while(var4.hasNext()) {
RestTemplateCustomizer customizer = (RestTemplateCustomizer)var4.next();
customizer.customize(restTemplate);
}
}
});
};
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RetryTemplate.class})
public static class RetryInterceptorAutoConfiguration {
public 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);
};
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({RetryTemplate.class})
public static class RetryAutoConfiguration {
public RetryAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})
static class LoadBalancerInterceptorConfig {
LoadBalancerInterceptorConfig() {
}
@Bean
public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return (restTemplate) -> {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
如何负载均衡
restTemplate.getForObject(requestUrl,String.class);
在调用的时候,会触发拦截器LoadBalancerInterceptor.intercept(),this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution)); LoadBalancerClient的实现类RibbonLoadBalancerClient,执行execute(String serviceId, LoadBalancerRequest request, Object hint),拦截器会获取目标的地址列表ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId)利用工厂模式,由serviceId获取ILoadBalancer 实例;,并通过负载规则Rule(默认轮训,即记录调用次数)实现目标服务的负载均衡的调取