Eureka client 源码初探

在搭好最简单的eurekaclient项目后,让我们来看看它里面的实现代码吧

首先 找到启动类EurekaClientAutoConfiguration,至于为什么是这个类,可以去了解一下springboot的autoconfig.

@Bean
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
	EurekaClientConfigBean client = new EurekaClientConfigBean();
	if ("bootstrap".equals(this.env.getProperty("spring.config.name"))) {
		// We don't register during bootstrap by default, but there will be another
		// chance later.
		client.setRegisterWithEureka(false);
	}
	return client;
}

注册EurekaClientConfigBean对象,看名字就知道是我们client的配置信息,里面包含了eureka-server的访问地址、发送心跳包的时间、延迟注册的时间等等一系列参数

@Bean
	@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
	public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
			ManagementMetadataProvider managementMetadataProvider) {
		String hostname = getProperty("eureka.instance.hostname");
		boolean preferIpAddress = Boolean
				.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
		String ipAddress = getProperty("eureka.instance.ip-address");
		boolean isSecurePortEnabled = Boolean
				.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));

		String serverContextPath = env.getProperty("server.servlet.context-path", "/");
		int serverPort = Integer
				.valueOf(env.getProperty("server.port", env.getProperty("port", "8080")));

		Integer managementPort = env.getProperty("management.server.port", Integer.class); // nullable.
		// should
		// be
		// wrapped
		// into
		// optional
		String managementContextPath = env
				.getProperty("management.server.servlet.context-path"); // nullable.
																		// should
		// be wrapped into
		// optional
		Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port",
				Integer.class); // nullable
		EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);

		instance.setNonSecurePort(serverPort);
		instance.setInstanceId(getDefaultInstanceId(env));
		instance.setPreferIpAddress(preferIpAddress);
		instance.setSecurePortEnabled(isSecurePortEnabled);
		if (StringUtils.hasText(ipAddress)) {
			instance.setIpAddress(ipAddress);
		}

		if (isSecurePortEnabled) {
			instance.setSecurePort(serverPort);
		}

		if (StringUtils.hasText(hostname)) {
			instance.setHostname(hostname);
		}
		String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path");
		String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path");

		if (StringUtils.hasText(statusPageUrlPath)) {
			instance.setStatusPageUrlPath(statusPageUrlPath);
		}
		if (StringUtils.hasText(healthCheckUrlPath)) {
			instance.setHealthCheckUrlPath(healthCheckUrlPath);
		}

		ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort,
				serverContextPath, managementContextPath, managementPort);

		if (metadata != null) {
			instance.setStatusPageUrl(metadata.getStatusPageUrl());
			instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
			if (instance.isSecurePortEnabled()) {
				instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
			}
			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;
	}

实例化eureka-client对象,获取我们在属性文件中的配置。

@Bean
public DiscoveryClient discoveryClient(EurekaClient client,
		EurekaClientConfig clientConfig) {
	return new EurekaDiscoveryClient(client, clientConfig);
}

实例化DiscoveryClient 对象,DiscoveryClient 对象中包含了服务注册、服务续约、发送心跳包的一系列方法。

服务注册流程:
在这里插入图片描述

/**
 * Register with the eureka service by making the appropriate REST call.
 */
boolean register() throws Throwable {
    logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
    EurekaHttpResponse<Void> httpResponse;
    try {
        httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
    } catch (Exception e) {
        logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
        throw e;
    }
    if (logger.isInfoEnabled()) {
        logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
    }
    return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}

httpResponse = eurekaTransport.registrationClient.register(instanceInfo)
register一共有俩种实现方式分别为:
a. AbstractJerseyEurekaHttpClient 抽象类

@Override
    public EurekaHttpResponse<Void> register(InstanceInfo info) {
        String urlPath = "apps/" + info.getAppName();
        ClientResponse response = null;
        try {
            Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder();
            addExtraHeaders(resourceBuilder);
            response = resourceBuilder
                    .header("Accept-Encoding", "gzip")
                    .type(MediaType.APPLICATION_JSON_TYPE)
                    .accept(MediaType.APPLICATION_JSON)
                    .post(ClientResponse.class, info);
            return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build();
        } finally {
            if (logger.isDebugEnabled()) {
                logger.debug("Jersey HTTP POST {}/{} with instance {}; statusCode={}", serviceUrl, urlPath, info.getId(),
                        response == null ? "N/A" : response.getStatus());
            }
            if (response != null) {
                response.close();
            }
        }
    }

b. RestTemplateEurekaHttpClient

@Override
public EurekaHttpResponse<Void> register(InstanceInfo info) {
	String urlPath = serviceUrl + "apps/" + info.getAppName();

	HttpHeaders headers = new HttpHeaders();
	headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
	headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

	ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST,
			new HttpEntity<>(info, headers), Void.class);

	return anEurekaHttpResponse(response.getStatusCodeValue())
			.headers(headersOf(response)).build();
}

以上俩个实现方法通过向eureka-server发送请求注册自身,client本身会根据返回的状态是否是204来验证是否注册成功。

DiscoveryClient类中还包含了以下一些方法:
registerHealthCheck 注册状态检查
renew() 发送心跳包,renew在初始化定时器时被创建,定时器默认每隔30执行一次。
在这里插入图片描述
shutdown() 关闭client服务,通知eureka-server剔除当前client实例
unregister() 服务下线
fetchRegistry 抓取注册信息
getAndStoreFullRegistry 缓存注册信息到本地
cancelScheduledTasks 关闭定时任务

以上方法的具体代码感兴趣可以自行查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值