Discovery(https://github.com/Nepxion/Discovery)是一个基于spring cloud的,可以执行蓝绿,灰度,路由等功能的一个框架。 功能就是在一个服务在线上有多个版本存在的时候,可以通过指定不同的版本,让流量流向不同的版本。
大致的实现方式如下:
spring cloud本身提供了一些组件,比如feigin,discoveryclient ribbon,resttemple完成了服务的注册,发现,负载,调用,Discovery框架对这些实现进行了增强,比如通过spring的addBeanPostProcessor()
// 所有 bean 都构造完之后调用
applicationContext.getBeanFactory().addBeanPostProcessor(new InstantiationAwareBeanPostProcessorAdapter() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 如果是DiscoveryClient类型
if (bean instanceof DiscoveryClient) {
// 获取类型
DiscoveryClient discoveryClient = (DiscoveryClient) bean;
// 将类型作为参数传入, 这里很重要, 在这里就完成了适配。
return new DiscoveryClientDecorator(discoveryClient, applicationContext);
} else {
return afterInitialization(applicationContext, bean, beanName);
}
}
});
DiscoveryClientDecorator则是继承了DiscoveryClient,并重写了其中的方法
@Override
public List getInstances(String serviceId) {
// 根据服务 Id, 调用spring cloud的方法获取所有的服务实例
List instances = getRealInstances(serviceId);
// 开关是否开启
Boolean discoveryControlEnabled = PluginContextAware.isDiscoveryControlEnabled(environment);
if (discoveryControlEnabled) {
try {
DiscoveryListenerExecutor discoveryListenerExecutor = applicationContext.getBean(DiscoveryListenerExecutor.class);
/**
* 应该是完成了核心的逻辑,
* instances 直接被传递了出去, 所以这里在内部实现上, 应该是有调用 remove 方法。
*
*
*/
discoveryListenerExecutor.onGetInstances(serviceId, instances);
} catch (BeansException e) {
// LOG.warn("Get bean for DiscoveryListenerExecutor failed, ignore to executor listener");
}
}
进入到具体的方法内部,就是根据一些规则和配置,从所有服务提供者中,选择出一批符合要求的服务实例(IP,port)
Discovery的大概流程如下:
- 注册时,判断了已经注册的实例数。
- 获取服务实例的时候,根据规则定义,返回了符合要求的实例。
- 再根据规则定义,对返回的实例数进行了负载。
- 对resttemplate进行了增强,让http的head可以传递下去。