spring-cloud-kubernetes背后的三个关键知识点

/**

  • 返回远程调用的结果

  • @return

*/

@RequestMapping(“/getservicedetail”)

public String getUri(

@RequestParam(value = “servicename”, defaultValue = “”) String servicename) {

return “Service [” + servicename + "]'s instance list : " + JSON.toJSONString(discoveryClient.getInstances(servicename));

}

/**

  • 返回发现的所有服务

  • @return

*/

@RequestMapping(“/services”)

public String services() {

return this.discoveryClient.getServices().toString()

  • ", "

  • new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date());

}

}

上述代码中,我们并没有写创建DiscoveryClient实例的代码,discoveryClient从何而来?

这一切,要从DiscoveryController.java所在项目的pom.xml说起;

  1. 在pom.xml中,有对spring-cloud-kubernetes框架的依赖配置:

org.springframework.cloud

spring-cloud-kubernetes-discovery

1.0.1.RELEASE

  1. 打开spring-cloud-kubernetes-discovery的源码,地址是:https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-discovery ,在这个工程中发现了文件spring.factories:

在这里插入图片描述

  1. spring容器启动时,会寻找classpath下所有spring.factories文件(包括jar文件中的),spring.factories中配置的所有类都会实例化,我们在开发springboot时常用到的XXX-starter.jar就用到了这个技术,效果是一旦依赖了某个starter.jar很多功能就在spring初始化时候自动执行了(例如mysql的starter,启动时会连接数据库),关于此技术的详情,请参考以下三篇文章:

《自定义spring boot starter三部曲之一:准备工作》

《自定义spring boot starter三部曲之二:实战开发》

《自定义spring boot starter三部曲之三:源码分析spring.factories加载过程》

  1. spring.factories文件中有两个类:KubernetesDiscoveryClientAutoConfiguration和KubernetesDiscoveryClientConfigClientBootstrapConfiguration都会被实例化;

  2. 先看KubernetesDiscoveryClientConfigClientBootstrapConfiguration,很简单的源码,KubernetesAutoConfiguration和KubernetesDiscoveryClientAutoConfiguration这两个类会被实例化:

/**

  • Bootstrap config for Kubernetes discovery config client.

  • @author Zhanwei Wang

*/

@Configuration

@ConditionalOnProperty(“spring.cloud.config.discovery.enabled”)

@Import({ KubernetesAutoConfiguration.class,

KubernetesDiscoveryClientAutoConfiguration.class })

public class KubernetesDiscoveryClientConfigClientBootstrapConfiguration {

}

  1. 在KubernetesAutoConfiguration的源码中,会实例化一个重要的类:DefaultKubernetesClient,如下:

@Bean

@ConditionalOnMissingBean

public KubernetesClient kubernetesClient(Config config) {

return new DefaultKubernetesClient(config);

}

  1. 再看KubernetesDiscoveryClientAutoConfiguration源码,注意kubernetesDiscoveryClient方法,这里面实例化了DiscoveryController所需的DiscoveryClient接口实现,还要重点关注的地方是KubernetesClient参数的值,是上面提到的DefaultKubernetesClient对象:

@Bean

@ConditionalOnMissingBean

@ConditionalOnProperty(name = “spring.cloud.kubernetes.discovery.enabled”, matchIfMissing = true)

public KubernetesDiscoveryClient kubernetesDiscoveryClient(KubernetesClient client,

KubernetesDiscoveryProperties properties,

KubernetesClientServicesFunction kubernetesClientServicesFunction,

DefaultIsServicePortSecureResolver isServicePortSecureResolver) {

return new KubernetesDiscoveryClient(client, properties,

kubernetesClientServicesFunction, isServicePortSecureResolver);

}

  1. 至此,第一个问题算是弄清楚了:我们编写的DiscoveryController类所需的DiscoveryClient接口实现类是KubernetesDiscoveryClient,用到的是spring规范中的spring.factories

  2. 另外有一点很重要,下面要用到的:KubernetesDiscoveryClient有个成员变量是KubernetesClient,该变量的值是DefaultKubernetesClient实例;

接下来看第二个问题;

java应用怎么能取得所在kubernetes的服务信息

  1. 看看DiscoveryController是如何获取所在kubernetes的服务信息的:

@RequestMapping(“/services”)

public String services() {

return this.discoveryClient.getServices().toString()

  • ", "

  • new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date());

}

如上所示,discoveryClient.getServices()方法返回了所有kubernetes的服务信息;

2. discoveryClient对应的类是spring-cloud-kubernetes项目的KubernetesDiscoveryClient.java,看方法:

public List getServices(Predicate filter) {

return this.kubernetesClientServicesFunction.apply(this.client).list().getItems()

.stream().filter(filter).map(s -> s.getMetadata().getName())

.collect(Collectors.toList());

}

这段代码的关键在于this.kubernetesClientServicesFunction.apply(this.client).list(),先看KubernetesClientServicesFunction实例的初始化过程,在KubernetesDiscoveryClientAutoConfiguration类中:

@Bean

public KubernetesClientServicesFunction servicesFunction(

KubernetesDiscoveryProperties properties) {

if (properties.getServiceLabels().isEmpty()) {

return KubernetesClient::services;

}

return (client) -> client.services().withLabels(properties.getServiceLabels());

}

KubernetesClientServicesFunction是个lambda表达式,用于KubernetesClient的时候,返回KubernetesClient.services()的结果,如果指定了标签过滤,就用指定的标签来做过滤(也就是kubernetes中的标签选择器的效果)

因此,数据来源其实就是上面的this.client,调用其services方法的返回结果;

3. KubernetesDiscoveryClient.getServices方法中的this.client是什么呢?分析前面的问题时已经提到过了,就是DefaultKubernetesClient类的实例,所以,此时要去看DefaultKubernetesClient.services方法,发现client是ServiceOperationsImpl实例:

@Override

public MixedOperation<Service, ServiceList, DoneableService, ServiceResource<Service, DoneableService>> services() {

return new ServiceOperationsImpl(httpClient, getConfiguration(), getNamespace());

}

  1. 接着看ServiceOperationsImpl.java,我们关心的是它的list方法,此方法在父类BaseOperation中找到:

public L list() throws KubernetesClientException {

try {

HttpUrl.Builder requestUrlBuilder = HttpUrl.get(getNamespacedUrl()).newBuilder();

String labelQueryParam = getLabelQueryParam();

if (Utils.isNotNullOrEmpty(labelQueryParam)) {

requestUrlBuilder.addQueryParameter(“labelSelector”, labelQueryParam);

}

String fieldQueryString = getFieldQueryParam();

if (Utils.isNotNullOrEmpty(fieldQueryString)) {

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

百度、字节、美团等大厂常见面试题

String fieldQueryString = getFieldQueryParam();

if (Utils.isNotNullOrEmpty(fieldQueryString)) {

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

[外链图片转存中…(img-bRlky08I-1714458441329)]

[外链图片转存中…(img-UayA4DzS-1714458441330)]

百度、字节、美团等大厂常见面试题

[外链图片转存中…(img-jv9dPTVO-1714458441330)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值