书接上篇 微服务负载均衡小能手-Ribbon 使用RIbion实现负载均衡远程调用
@Bean
@LoadBalanced
public RestTemplate restTemplate(){return new RestTemplate();
}
都知道没有@LoadBalanced注解前,RestTemplate就是一个简单的http请求工具类,贴上该注解,却能山鸡变凤凰,成为具有负载均衡的小能手,为啥呢?本篇就跟你讲讲为啥,开讲之前需要铺垫四个知识储备:
1>@Qualifier 2>SmartInitializingSingleton接口 3>ClientHttpRequestInterceptor拦截器 4>SpringBoot 自动配置
Spring 给@Qualifier注解赋予2个功能
熟悉的Spring的小伙伴应该能看懂下面的代码:
@Service
public class OrderServiceImpl implements IOrderService {@Autowiredprivate 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名字指定@Autowiredprivate IDiscountService discountService ; //折扣服务
}
@Qualifier("xxx") xxx是 Bean 的名称,@Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了,完美解决了接口多实现问题。
@Qualifier 注解的这个功能,开发中用途算广,但是Ribbon 负载均衡功能@LoadBalanced 注解刚好用到。
还是上面的接口案例,现在有个需求:将所有IDiscountService接口实现类添加到List集合中
@Autowiredprivate List list= Collections.emptyList();@Testpublic 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 list= Collections.emptyList();@Testpublic void testList() {for (IDiscountService discountService : list) {System.out.println(discountService.getClass());}}
执行后,会打印出所有的IDiscountService接口实现类
class com.langfeiyes.demo.Discount2ServiceImpl
到这,@Qualifier 注解知识点铺垫算介绍啦,下面看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("我被构建了...");}@Overridepublic void afterSingletonsInstantiated() {System.out.println("我被回调了....");}
}------------------@SpringBoot
class DemoApplication {@Beanpublic SomeBean someBean(){return new SomeBean();}}
查看打印返回值:
我被构建了...
我被回调了....
到这,SmartInitializingSingleton 接口知识点铺垫算介绍啦,下面看 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 {@Overridepublic 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自动配置用下图就可以讲清楚啦:
到这,@LoadBalanced 注解需要的知识储备算准备齐活了,下一篇就是@LoadBalanced注解的源码介绍啦。
上一篇: 《莎士比亚十四行诗》
下一篇: 五月的优美古诗词