/**
-
返回远程调用的结果
-
@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说起;
- 在pom.xml中,有对spring-cloud-kubernetes框架的依赖配置:
org.springframework.cloud
spring-cloud-kubernetes-discovery
1.0.1.RELEASE
- 打开spring-cloud-kubernetes-discovery的源码,地址是:https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-discovery ,在这个工程中发现了文件spring.factories:
- 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加载过程》
-
spring.factories文件中有两个类:KubernetesDiscoveryClientAutoConfiguration和KubernetesDiscoveryClientConfigClientBootstrapConfiguration都会被实例化;
-
先看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 {
}
- 在KubernetesAutoConfiguration的源码中,会实例化一个重要的类:DefaultKubernetesClient,如下:
@Bean
@ConditionalOnMissingBean
public KubernetesClient kubernetesClient(Config config) {
return new DefaultKubernetesClient(config);
}
- 再看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);
}
-
至此,第一个问题算是弄清楚了:我们编写的DiscoveryController类所需的DiscoveryClient接口实现类是KubernetesDiscoveryClient,用到的是spring规范中的spring.factories
-
另外有一点很重要,下面要用到的:KubernetesDiscoveryClient有个成员变量是KubernetesClient,该变量的值是DefaultKubernetesClient实例;
接下来看第二个问题;
java应用怎么能取得所在kubernetes的服务信息
- 看看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());
}
- 接着看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)]