写在前面的话
最近在研究Ribbon源码的过程中,一直想不明白@LoadBalanced注解的原理,因为我一直找不到解析这个注解的类在哪。
直接我看见了@LoadBalanced注解上还打了一个@Qualifier注解,我顿悟,这个注解肯定跟@Qualifier注解有关系
1、@Qualifier注解的作用
假设有一个接口UserService,该接口有两个实现类,分别为AUserServiceImpl,BUserServiceImpl,这两个实现类都注册为spring的bean,如下所示
public interface UserService {
}
@Service
public class AUserServiceImpl implements UserService {
}
@Service
public class BUserServiceImpl implements UserService {
}
那么在controller中依赖注入的时候,如果用@Autowired注解注入,则势必会报错,就像下面一样
@Autowired
private UserService userService;
因为@Autowired是按Bean的类型装配,而此时有两个UserService类型的Bean,则注入的时候spring不知道你到底想要注入哪个Bean,索性直接报错了
该问题有几种解决方法,如下:
方法一:
采用@Resource注解,如下所示:
@Resource
private UserService AUserServiceImpl;
方法二:
采用List类型,如下所示:
@Autowired
private List<UserService> userServiceList;
此时有再多的UserService类型的Bean也不怕了,因为统统都会被放到List里面去
方法三:
采用@Qualifier注解。Qualifier是合格者的意思,表示为多个实现类选一个合格者注入,如下所示
@Autowired
@Qualifier("AUserServiceImpl")
private UserService userService;
@Qualifier注解的基本作用就先讲到这了
2、Ribbon中的@LoadBalanced注解
本文的目的是利用Ribbon中@LoadBalanced注解,来介绍spring的@Qualifier注解的使用小技巧,不会Ribbon的小伙伴也能读懂,因此本文就不介绍Ribbon的相关知识了
有兴趣的小伙伴们可以看我的这篇文章,这里面有Ribbon的原理和实战相关的内容,非常详细 Spring Cloud教程 第二弹 客户端负载均衡Ribbon
@LoadBalanced注解的源码如下(@LoadBalanced注解上打了一个@Qualifier注解,因此@LoadBalanced是@Qualifier的子类):
package org.springframework.cloud.client.loadbalancer;
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;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
在Ribbon中有一个自动配置类,其关键代码如红框部分所示(别的不用看):
另外,使用过Ribbon的小伙伴们肯定都知道,还需要如下配置才能让负载均衡生效:
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
上述有三块代码,分别称为第一块代码、第二块代码、第三块代码
经过我一番思考,于是我大胆地提出猜想:
- 第一块代码中,由于@LoadBalanced是@Qualifier的子类,那么@LoadBalanced也具有@Qualifier的特性
- 第二块代码中,LoadBalancerAutoConfiguration类的restTemplates属性上打了@Autowired注解,表示将所有RestTemplate类型的Bean注入到该集合中,并且还打了@LoadBalanced注解,则注入的筛选条件是:具有负载均衡标识的RestTemplate
- 第三块代码中,恰恰用@Bean和@LoadBalanced注解声明了一个RestTemplate类型的bean
3、验证猜想
3.1、自定义注解
@Target({ ElementType.TYPE,ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalancedCopy {
}
3.2、定义Bean
现在接口UserService和五个实现类,五个实现类中有2个实现类打上@LoadBalancedCopy注解
public interface UserService {
}
@Service
public class AUserServiceImpl implements UserService {
}
@Service
@LoadBalancedCopy
public class BUserServiceImpl implements UserService {
}
@Service
public class CUserServiceImpl implements UserService {
}
@Service
@LoadBalancedCopy
public class DUserServiceImpl implements UserService {
}
@Service
public class EUserServiceImpl implements UserService {
}
3.3、注入
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
@LoadBalancedCopy
private List<UserService> userServiceList;
@RequestMapping("/beanInfo")
public void beanInfo(){
System.out.println(userServiceList.size());
for (UserService userService : userServiceList) {
System.out.println(userService.getClass().getName());
}
}
}
3,4、运行测试
访问http://localhost:8160/springboot-common-base/common/beanInfo 控制台打印信息如下
由此可见,我的猜想是正确的
总结
本文主要介绍了@Qualifier注解的作用,并且由Ribbon的@LoadBalanced注解,引出了@Qualifier注解的小技巧
顺带着也把@LoadBalanced注解的原理也讲了