Spring Cloud 近几年非常火,是微服务架构一站式解决方案,但是在某些特定场景的服务治理上还是有些欠缺,开源的强大就是我们可以站在巨人的肩膀上实现定制化功能。目前我也在我司的平台组进行相关微服务组件开发,对于遇到的需求和问题经过思考等整理了一些东西,为以后组件优化和升级做铺垫。
针对基于Eureka注册中心的扩展
目前比较流行的还是 Spring Cloud Netflix 这一套,因此可以利用Eureka注册中心做很大部分的扩展,本次就简单减少一下如何将自定义的元信息发布到Eureka上。
元数据的注册
之前有一篇文章聊到 Eureka Client 源码 , 我们就基于这一篇在简单的讲解一下思路。在org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
这个配置类中我们可以看到下面这一段代码
@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
ManagementMetadataProvider managementMetadataProvider) {
//省略代码
/**
* 这段代码就是本地初始化元数据的地方了
*
**/
if (metadata != null) {
instance.setStatusPageUrl(metadata.getStatusPageUrl());
instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
if (instance.isSecurePortEnabled()) {
instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
}
//我们可以使用 metadataMap 进行元数据的添加
Map<String, String> metadataMap = instance.getMetadataMap();
metadataMap.computeIfAbsent("management.port",
k -> String.valueOf(metadata.getManagementPort()));
}
else {
// without the metadata the status and health check URLs will not be set
// and the status page and health check url paths will not include the
// context path so set them here
if (StringUtils.hasText(managementContextPath)) {
instance.setHealthCheckUrlPath(
managementContextPath + instance.getHealthCheckUrlPath());
instance.setStatusPageUrlPath(
managementContextPath + instance.getStatusPageUrlPath());
}
}
setupJmxPort(instance, jmxPort);
return instance;
}
根据上面的代码,我们可以很轻松的看出添加元数据的地方,但是我们可以看到这个Bean的注册是不支持覆盖的。因此我们如果想要扩展还需要在注册Bean的地方下功夫,我这里是这样想的,重写一个配置 EurekaInstanceConfigBean
的Bean 在EurekaClientAutoConfiguration
并 将其设置为 @Primary
。这样后续的组件的依赖注入会采取咱们自定义的Bean,当然这样比较暴露。还有一种是在该组件初始化完成后,注册到Eureka之前,将其内容修改,这样做到了 解耦,无论Spring Cloud 如何更新,不影响我们元数据注册。
元数据的获取
这里获取元数据的接口,个人建议是直接用Spring Cloud原生的 组件去获取,主要就是 DiscoveryClient
这个接口。我们可以简单的看一下其中的一个实现类。
EurekaDiscoveryClient
中的两个方法
// 获取其元数据
@Override
public List<ServiceInstance> getInstances(String serviceId) {
List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,
false);
List<ServiceInstance> instances = new ArrayList<>();
for (InstanceInfo info : infos) {
instances.add(new EurekaServiceInstance(info));
}
return instances;
}
//获取所有注册服务实例名
@Override
public List<String> getServices() {
Applications applications = this.eurekaClient.getApplications();
if (applications == null) {
return Collections.emptyList();
}
List<Application> registered = applications.getRegisteredApplications();
List<String> names = new ArrayList<>();
for (Application app : registered) {
if (app.getInstances().isEmpty()) {
continue;
}
names.add(app.getName().toLowerCase());
}
return names;
}
我们可以自己实现组件,获取其对应的 注册Client ,然后通过实例名获取其实例的信息。
小结
其实通过我们自定义的元数据,可以做相当多的微服务扩展,通过原生的Spring Cloud 组件的接口方法,去做定制化开发,这样可以做到不管Spring Cloud 如何更新,接口大部分的情况下是不会改变的,因此减少了升级整合的工作量,做开发适应自己公司业务的微服务平台。这里就不一一举例了,其实就是一种新的元数据管理方式,通过注册中心,动态的更新到每一个微服务上,这里注意,跟微服务的统一配置是有区别的。
网友评论