引言
书接上篇 微服务负载均衡小能手-Ribbon 使用RIbion实现负载均衡远程调用
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
	return new RestTemplate();
}都知道没有@LoadBalanced注解前,RestTemplate就是一个简单的http请求工具类,贴上该注解,却能山鸡变凤凰,成为具有负载均衡的小能手,为啥呢?本篇就跟你讲讲为啥,开讲之前需要铺垫四个知识储备:
1>@Qualifier 2>SmartInitializingSingleton接口 3>ClientHttpRequestInterceptor拦截器 4>SpringBoot 自动配置
@Qualifier注解详解
Spring 给@Qualifier注解赋予2个功能
1:根据Bean名字注入属性
熟悉的Spring的小伙伴应该能看懂下面的代码:
@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private IDiscountService discountService ;  //折扣服务
}order业务层需要引入折扣业务逻辑,其中的@Autowired 能让Spring将容器中有且唯一的IDiscountService 接口实现类注入到OrderServiceImpl 中。很理想,真实情况是电商项目中的商品折扣种类很多,IDiscountService 接口实现类不会唯一,当spring容器中存在多个IDiscountService 接口实例时,上面代码执行肯定会报错
Field discountService in xxxx.OrderServiceImpl required a single bean, but n were found:
怎么办呢?此时@Qualifier注解就起作用啦。
public interface IDiscountService  {
}
@Service("discount1Service")
public class Discount1ServiceImpl  implements IDiscountService  {
}
@Service("discount2Service")
public class Discount2ServiceImpl implements IDiscountService  {
}在定义IDiscountService 接口实现类时,给这些实现类指定Bean名:discount1Service discount2Service 后续使用时,使用@Qualifier("bean名称")直接指定
@Service
public class OrderServiceImpl implements IOrderService {
    @Qualifier("discount2Service")  //根据bean名字指定
    @Autowired
    private IDiscountService discountService ;  //折扣服务
}@Qualifier("xxx") xxx是 Bean 的名称,@Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了,完美解决了接口多实现问题。
2:Bean筛选标记符
@Qualifier 注解的这个功能,开发中用途算广,但是Ribbon 负载均衡功能@LoadBalanced 注解刚好用到。
还是上面的接口案例,现在有个需求:将所有IDiscountService接口实现类添加到List集合中
    @Autowired
    private List<IDiscountService> list= Collections.emptyList();
    @Test
    public void testList() {
        for (IDiscountService discountService : list) {
            System.out.println(discountService.getClass());
        }
    }执行后,会打印出所有的IDiscountService接口实现类
class com.langfeiyes.demo.Discount1ServiceImpl
 class com.langfeiyes.demo.Discount2ServiceImpl
ok,没问题,我们升级一下需求:只需要Discount1ServiceImpl实现类添加到List集合中
 此时就需要使用@Qualifier 注解的筛选功能了。
public interface IDiscountService  {
}
//不贴,没有筛选标记
@Service("discount1Service")
public class Discount1ServiceImpl  implements IDiscountService  {
}
@Qualifier  //贴,筛选标记
@Service("discount2Service")
public class Discount2ServiceImpl implements IDiscountService  {
}2个接口实现类,只有Discount2ServiceImpl 贴上@Qualifier 标记,集合收集时,配合@Autowired可以实现自动筛选功能
    @Qualifier
    @Autowired(required = false)
    private List<IDiscountService> list= Collections.emptyList();
    @Test
    public void testList() {
        for (IDiscountService discountService : list) {
            System.out.println(discountService.getClass());
        }
    }执行后,会打印出所有的IDiscountService接口实现类
class com.langfeiyes.demo.Discount2ServiceImpl
到这,@Qualifier 注解知识点铺垫算介绍啦,下面看SmartInitializingSingleton 接口
SmartInitializingSingleton 接口
先看下该SmartInitializingSingleton源码
public interface SmartInitializingSingleton {
	void afterSingletonsInstantiated();
}SmartInitializingSingleton接口里面只有一个方法:afterSingletonsInstantiated 从方法名也大概看出作用。SmartInitializingSingleton是Spring提供的钩子接口,实现该接口的Bean会在Spring容器初始化所有Bean之后,由容器直接回调afterSingletonsInstantiated 方法。注意:回调的是所有单例Bean。
来一个例子演示一下
public class SomeBean  implements SmartInitializingSingleton {
    public SomeBean(){
        System.out.println("我被构建了...");
    }
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("我被回调了....");
    }
}
------------------
@SpringBoot
class DemoApplication {
    @Bean
    public SomeBean someBean(){
        return new SomeBean();
    }
}查看打印返回值:
我被构建了...
 我被回调了....
到这,SmartInitializingSingleton 接口知识点铺垫算介绍啦,下面看 ClientHttpRequestInterceptor拦截器
ClientHttpRequestInterceptor拦截器
截止目前,Spring支持3种http请求拦截器器,分别是
HandlerInterceptor :SpringMVC中组件,拦截普通客户端发起请求,比如:浏览器 ,使用最广的http请求拦截器
ClientHttpRequestInterceptor:spring-web组件,拦截是RestTemplate工具getForEntry/getForObject 发起的http请求,所以常被称之RestTemplate拦截器
RequestInterceptor:spring-cloud-feign组件,拦截是feign发起的远程调用请求,所以称之为Feign拦截器。
本篇重点讲ClientHttpRequestInterceptor拦截器,其他拦截有机会我们再深入。
先看下ClientHttpRequestInterceptor接口源码
@FunctionalInterface
public interface ClientHttpRequestInterceptor {
	ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
			throws IOException;
}ClientHttpRequestInterceptor 接口为函数接口,只有一个intercept拦截方法,在定制拦截器时我们可以根据业务需求为getForEntry/getForObject 方法请求添加额外参数。
需求:getForEntry/getForObject 发起的请求都需要带上身份令牌token
public class RestTokenInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        HttpHeaders headers = request.getHeaders();
        headers.add("token","xxxx");
        return execution.execute(request,body);
    }
}到这,ClientHttpRequestInterceptor拦截器知识点铺垫算介绍啦,下面看:SpringBoot自动配置
SpringBoot自动配置
SpringBoot自动配置之前也写过来,有兴趣的朋友,可以看浅谈SpringBoot 入门合集。
SpringBoot自动配置用下图就可以讲清楚啦:

到这,@LoadBalanced 注解需要的知识储备算准备齐活了,下一篇就是@LoadBalanced注解的源码介绍啦。














![[附源码]Python计算机毕业设计Django个性化产品服务管理系统论文](https://img-blog.csdnimg.cn/c4ee09901b214c28915167148dbdf5e0.png)




