在使用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,消除歧义。

@LoadBalanced注解原理的更多相关文章

  1. 深入理解@LoadBalanced注解的实现原理与客户端负载均衡

    前提 在阅读这篇博客之前,希望你对SpringCloud套件熟悉和理解,更希望关注下微服务开发平台 概述 在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate ...

  2. Spring 注解原理(三)@Qualifier @Value

    Spring 注解原理(三)@Qualifier @Value Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 一.Aut ...

  3. 为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】

    每篇一句 你应该思考:为什么往往完成比完美更重要? 前言 在Spring Cloud微服务应用体系中,远程调用都应负载均衡.我们在使用RestTemplate作为远程调用客户端的时候,开启负载均衡极其 ...

  4. Java Android 注解(Annotation) 及几个常用开源项目注解原理简析

    不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...

  5. java基础解析系列(六)---深入注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer ja ...

  6. Spring 注解原理(一)组件注册

    Spring 注解原理(一)组件注册 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 当我们需要使用 Spring 提供的 ...

  7. java基础解析系列(六)---注解原理及使用

    java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer缓存及 ...

  8. Spring 中常用注解原理剖析

    前言 Spring 框架核心组件之一是 IOC,IOC 则管理 Bean 的创建和 Bean 之间的依赖注入,对于 Bean 的创建可以通过在 XML 里面使用 <bean/> 标签来配置 ...

  9. Spring注解原理

    一.注解的基本概念和原理及其简单实用 注解(Annotation)提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析注解 ...

  10. 浅谈SpringBoot核心注解原理

    SpringBoot核心注解原理 今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配置 ...

随机推荐

  1. Go_Goroutine详解

    Goroutine详解 goroutine的概念类似于线程,但 goroutine是由Go的运行时(runtime)调度和管理的.Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU ...

  2. Filter 筛选器(二)之 ExceptionFilter

    public class MyExceptionFilter : IAsyncExceptionFilter { private readonly ILogger<MyExceptionFilt ...

  3. Spring MVC(配置、入门)

      Spring MVC 框架的模块    什么是Spring的MVC框架? Spring 配备构建Web 应用的全功能MVC框架.Spring可以很便捷地和其他MVC框架集成,如Struts,Spr ...

  4. 聊一聊被 .NET程序员 遗忘的 COM 组件

    一:背景 1.讲故事 最近遇到了好几起和 COM 相关的Dump,由于对 COM 整体运作不是很了解,所以分析此类dump还是比较头疼的,比如下面这个经典的 COM 调用栈. 0:044> ~~ ...

  5. 通过 Github Action 实现定时推送天气预报

    偶然间,看到 GitHub Actions 教程:定时发送天气邮件 - 阮一峰的网络日志 这篇文章,没错,这个正好能打发自己的折腾之心,也能通过代码给生活引入一些变化. 还是在这里简单记录一下实现过程 ...

  6. echarts的使用 超好用的报表制作、数据的图形化展示

    地址链接:https://echarts.apache.org/zh/index.html 1.图形选择 2.对应的js代码

  7. 如何解读Linux Kernel OOPS信息

    OOPS信息解读 root@firefly:~/mnt/module# insmod oops_module.ko [ 867.140514] Unable to handle kernel NULL ...

  8. UE优化性能

    UE 优化 参考:风恋残雪的博客 Stat unit 启动一个非Debug的游戏进程 打开控制台输入 Stat UNIT .PC端 ` , Android 四指点击 正常的渲染状态: 名称 功能 Fr ...

  9. 2022icpc新疆省赛

    菜鸡第一次打icpc 记录一下历程 习惯#define int long long 以下皆是按照我认为的难易顺序排序 K. 看题意大概就是说求从L加到R 1 ios::sync_with_stdio( ...

  10. C#多线程之高级篇(上)

    前言 抛开死锁不谈,只聊性能问题,尽管锁总能粗暴的满足同步需求,但一旦存在竞争关系,意味着一定会有线程被阻塞,竞争越激烈,被阻塞的线程越多,上下文切换次数越多,调度成本越大,显然在高并发的场景下会损害 ...