在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,就能让这个RestTemplate在请求时拥有客户端负载均衡的能力:

@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
  • 1
  • 2
  • 3
  • 4
  • 5

是不是很神奇?打开@LoadBalanced的注解源码,并没有什么特殊的东东

package org.springframework.cloud.client.loadbalancer;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target; /**
  • 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 {

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

唯一不同的地方就是多了一个@Qulifier注解.

搜索@LoadBalanced注解的使用地方,发现只有一处使用了,在LoadBalancerAutoConfiguration这个自动装配类中:

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList(); @Bean

public SmartInitializingSingleton loadBalancedRestTemplateInitializer(

final List<RestTemplateCustomizer> customizers) {

return new SmartInitializingSingleton() {

@Override

public void afterSingletonsInstantiated() {

for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {

for (RestTemplateCustomizer customizer : customizers) {

customizer.customize(restTemplate);

}

}

}

};

} @Autowired(required = false)

private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList(); @Bean

@ConditionalOnMissingBean

public LoadBalancerRequestFactory loadBalancerRequestFactory(

LoadBalancerClient loadBalancerClient) {

return new LoadBalancerRequestFactory(loadBalancerClient, transformers);

} @Configuration

@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")

static class LoadBalancerInterceptorConfig {

@Bean

public LoadBalancerInterceptor ribbonInterceptor(

LoadBalancerClient loadBalancerClient,

LoadBalancerRequestFactory requestFactory) {

return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);

} @Bean

@ConditionalOnMissingBean

public RestTemplateCustomizer restTemplateCustomizer(

final LoadBalancerInterceptor loadBalancerInterceptor) {

return new RestTemplateCustomizer() {

@Override

public void customize(RestTemplate restTemplate) {

List<ClientHttpRequestInterceptor> list = new ArrayList<>(

restTemplate.getInterceptors());

list.add(loadBalancerInterceptor);

restTemplate.setInterceptors(list);

}

};

}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

这段自动装配的代码的含义不难理解,就是利用了RestTempllate的拦截器,使用RestTemplateCustomizer对所有标注了@LoadBalanced的RestTemplate Bean添加了一个LoadBalancerInterceptor拦截器,而这个拦截器的作用就是对请求的URI进行转换获取到具体应该请求哪个服务实例ServiceInstance。

那么为什么

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
  • 1
  • 2
  • 3

这个restTemplates能够将所有标注了@LoadBalanced的RestTemplate自动注入进来呢?这就要说说@Autowired注解和@Qualifier这两个注解了。

大家日常使用很多都是用@Autowired来注入一个bean,其实@Autowired还可以注入List和Map,比如我定义两个Bean:

@RestController
public class MyController {
<span class="token annotation punctuation">@Autowired</span><span class="token punctuation">(</span>required <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> users <span class="token operator">=</span> <span class="token class-name">Collections</span><span class="token punctuation">.</span><span class="token function">emptyList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@Autowired</span><span class="token punctuation">(</span>required <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> userMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/list"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">listUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> users<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/map"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">mapUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> userMap<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在controller中通过:

@Autowired(required = false)
private List<User> users = Collections.emptyList(); @Autowired(required = false)

private Map<String,User> userMap = new HashMap<>();
  • 1
  • 2
  • 3
  • 4
  • 5

就可以自动将两个bean注入进来,当注入map的时候,map的key必须是String类型,然后bean name将作为map的key,本例,map中将有两个key分别为user1和user2,value分别为对应的User Bean实例。

访问http://localhost:8080/map:

{
"user1": {
"id": "1",
"name": "a"
},
"user2": {
"id": "2",
"name": "b"
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

访问http://localhost:8080/list:

[
{
"id": "1",
"name": "a"
},
{
"id": "2",
"name": "b"
}
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后我们给user1和user2分别打上@Qualifier修饰符:

@Bean("user1")
@Qualifier("valid")
User user1() {
return new User("1", "a");
} @Bean("user2")

@Qualifier("invalid")

User user2() {

return new User("2", "b");

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后将controller中的user list 和user map分别也打上@Qualifier修饰符:

@RestController
public class MyController {
<span class="token annotation punctuation">@Autowired</span><span class="token punctuation">(</span>required <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Qualifier</span><span class="token punctuation">(</span><span class="token string">"valid"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> users <span class="token operator">=</span> <span class="token class-name">Collections</span><span class="token punctuation">.</span><span class="token function">emptyList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@Autowired</span><span class="token punctuation">(</span>required <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Qualifier</span><span class="token punctuation">(</span><span class="token string">"invalid"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> userMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/list"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">listUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> users<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/map"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">mapUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> userMap<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

那么所有标注了@Qualifier(“valid”)的user bean都会自动注入到List users中去(本例是user1),所有标注了@Qualifier(“invalid”)的user bean都会自动注入到Map<String,User> userMap中去(本例是user2),我们再次访问上面两个url:

访问http://localhost:8080/list:

[
{
"id": "1",
"name": "a"
}
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

访问http://localhost:8080/map:


{
"user2": {
"id": "2",
"name": "b"
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

看到这里我们可以理解@LoadBalanced的用处了,其实就是一个修饰符,和@Qualifier一样,比如我们给user1打上@LoadBalanced:

@Bean("user1")
@LoadBalanced
User user1() {
return new User("1", "a");
} @Bean("user2")

User user2() {

return new User("2", "b");

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后controller中给List users打上@LoadBalanced注解:

@Autowired(required = false)
@LoadBalanced
private List<User> users = Collections.emptyList();
  • 1
  • 2
  • 3

访问http://localhost:8080/list:

[
{
"id": "1",
"name": "a"
}
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

和@Qualifier注解效果一样,只有user1被注入进了List,user2没有修饰符,没有被注入进去。

另外当spring容器中有多个相同类型的bean的时候,可以通过@Qualifier来进行区分,以便在注入的时候明确表明你要注入具体的哪个bean,消除歧义。

最新文章

  1. [No0000A7]批处理经常用到的变量及批处理&gt;NUL详细介绍
  2. .NET/ASP.NET MVC(模块化开发AraeRegistration)
  3. Hibernate一对一、一对多、多对多注解映射配置
  4. springboot+druid
  5. android 瀑布流效果 保存地址
  6. Install Sogoupinyin in Ubuntu
  7. zabbix 3.0快速安装简介(centos 7)
  8. [计算机图形学] 基于C#窗口的Bresenham直线扫描算法、种子填充法、扫描线填充法模拟软件设计(二)
  9. laravel elixir
  10. android怎么换背景图片
  11. spring和redis的整合-超越昨天的自己系列(7)
  12. span里设置高度
  13. 各种编码之间的关系以及getBytes的使用
  14. php ajax 下拉加载数据
  15. TagHelper+Layui封装组件之Radio单选框
  16. SQLServer之修改用户自定义数据库用户
  17. 基于GPS数据建立隐式马尔可夫模型预测目的地
  18. Codeforces 1136E Nastya Hasn&#39;t Written a Legend 线段树
  19. : LDAP &amp; Implementation
  20. 【转】C/C++内存泄漏及检测

热门文章

  1. NOIP2003 普及组 洛谷P1045 麦森数 (快速幂+高精度)
  2. windows下利用_popen,_wpoen创建管道进行系统命令输出数据
  3. java常用注解校验参数
  4. aws上传文件、删除文件、图像识别
  5. JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
  6. LeetCode------两数之和(3)【数组】
  7. C语言/python实现定时关机
  8. 测试架构师CAP原理(最简单)
  9. 苹果iOS App上架流程,非iOS开发人员上架教程
  10. springboot如何处理矩阵参数类型的url