服务治理Consul之源码解析

Consul初始化过程中涉及三个核心包,分别为spring-cloud-consul-core、spring-cloud-consul-config、spring-cloud-consul-discovery。

spring-cloud-consul-core包涉及核心类ConsulAutoConfiguration。

spring-cloud-consul-discovery包涉及核心类如下:ConsulServiceRegistryAutoConfiguration、ConsulAutoServiceRegistrationAutoConfiguration等。

1.核心包core涉及的核心类ConsulAutoConfiguration

public class ConsulAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean
	public ConsulProperties consulProperties() {
		return new ConsulProperties();
	}
	
	@Bean
	@ConditionalOnMissingBean
	public ConsulClient consulClient(ConsulProperties consulProperties) {
		final int agentPort = consulProperties.getPort();
		final String agentHost = !StringUtils.isEmpty(consulProperties.getScheme())
				? consulProperties.getScheme() + "://" + consulProperties.getHost()
				: consulProperties.getHost();
		...
		return new ConsulClient(agentHost, agentPort);
	}
}

ConsulProperties:控制服务是否接入consul集群的开关、服务注册端口8500等信息。

2.核心包discovery的核心类

2.1.ConsulServiceRegistryAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.enabled",matchIfMissing = true)
@AutoConfigureBefore(ServiceRegistryAutoConfiguration.class)
public class ConsulServiceRegistryAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public ConsulServiceRegistry consulServiceRegistry(ConsulClient consulClient,
			ConsulDiscoveryProperties properties, HeartbeatProperties heartbeatProperties,
			@Autowired(required = false) TtlScheduler ttlScheduler) {
		return new ConsulServiceRegistry(consulClient, properties, ttlScheduler,
				heartbeatProperties);
	}

	@Bean
	@ConditionalOnMissingBean
	public HeartbeatProperties heartbeatProperties() {
		return new HeartbeatProperties();//服务与consul服务端之间心跳检测相关配置
	}

	@Bean
	@ConditionalOnMissingBean
	public ConsulDiscoveryProperties consulDiscoveryProperties(InetUtils inetUtils) {
		return new ConsulDiscoveryProperties(inetUtils);
	}

}

ConsulDiscoveryProperties:服务注册相关属性配置。包括健康检查地址。

2.2.ConsulAutoServiceRegistrationAutoConfiguration

服务注册的核心类。该类的核心目的是初始化事件监听器ConsulAutoServiceRegistrationListener。#5

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.cloud.consul.discovery.ConsulLifecycle")
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,ConsulServiceRegistryAutoConfiguration.class })
public class ConsulAutoServiceRegistrationAutoConfiguration {

	@Autowired
	AutoServiceRegistrationProperties autoServiceRegistrationProperties;

	@Bean
	@ConditionalOnMissingBean
	public ConsulAutoServiceRegistration consulAutoServiceRegistration(
			ConsulServiceRegistry registry,AutoServiceRegistrationProperties asrp,
			ConsulDiscoveryProperties properties,ConsulAutoRegistration consulRegistration) {
		return new ConsulAutoServiceRegistration(registry,asrp, properties, consulRegistration);
	}
	// 真正触发注册功能。
	//监听器构造器构造参数:ConsulAutoServiceRegistration
	//ConsulAutoServiceRegistration构造器构造参数包含ConsulAutoRegistration实例化
	@Bean
	public ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener(
			ConsulAutoServiceRegistration registration) {
		return new ConsulAutoServiceRegistrationListener(registration);
	}
	
	@Bean
	@ConditionalOnMissingBean
	public ConsulAutoRegistration consulRegistration(
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,
			ConsulDiscoveryProperties properties, ApplicationContext applicationContext,
			ObjectProvider<List<ConsulRegistrationCustomizer>> registrationCustomizers,
			ObjectProvider<List<ConsulManagementRegistrationCustomizer>> managementRegistrationCustomizers,
			HeartbeatProperties heartbeatProperties) {
		return ConsulAutoRegistration.registration(autoServiceRegistrationProperties,
				properties, applicationContext, registrationCustomizers.getIfAvailable(),
				managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties);
	}
	...
}

3.2.1、ConsulAutoRegistration

如果NewService其port属性为null,并且并没有Management相关属性的显式配置,则健康检查地址为:

http://IP:server.port/actuator/health
public class ConsulAutoRegistration extends ConsulRegistration {

	public static ConsulAutoRegistration registration(
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,
			ConsulDiscoveryProperties properties, ApplicationContext context,
			List<ConsulRegistrationCustomizer> registrationCustomizers,
			List<ConsulManagementRegistrationCustomizer> managementRegistrationCustomizers,
			HeartbeatProperties heartbeatProperties) {
		// NewService是consul对应用服务实例的抽象
		NewService service = new NewService();
		//优先获取properties中serviceName,其次spring.application.name,再次application。目的就是定义注册中心中服务名
		String appName = getAppName(properties, context.getEnvironment());
		service.setId(getInstanceId(properties, context));
		if (!properties.isPreferAgentAddress()) {
			service.setAddress(properties.getHostname());
		}
		service.setName(normalizeForDns(appName));
		service.setTags(createTags(properties));
		if (properties.getPort() != null) {
			service.setPort(properties.getPort());
			setCheck(service, autoServiceRegistrationProperties, properties, context,
					heartbeatProperties);
		}

		ConsulAutoRegistration registration = new ConsulAutoRegistration(service,
				autoServiceRegistrationProperties, properties, context,
				heartbeatProperties, managementRegistrationCustomizers);
		customize(registrationCustomizers, registration);
		return registration;
	}
	...
}

NewService中静态类check表示consul健康检查相关设置。除非的前提是配置类ConsulDiscoveryProperties中端口号不能为空。

注意:配置类ConsulDiscoveryProperties中端口号为server.port。

check的相关属性赋值存在两种情况,要不是采取默认值,要不使用Management配置相关属性。

如果选择Management配置相关属性存在三个条件,如下:

  1. AutoServiceRegistrationProperties配置类其属性registerManagement为true【默认值】。
  2. ManagementServerProperties配置类的端口号不能为空。
  3. 并且不能和server.port一致。

再者,就是自定义健康检查接口api:优先选择配置类ConsulDiscoveryProperties中healthCheckUrl配置的值,否则选择默认值healthCheckPath = “/actuator/health”。

4、服务注册监听器之ConsulAutoServiceRegistrationListener

public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener {
	// ConsulAutoServiceRegistration
	private final ConsulAutoServiceRegistration autoServiceRegistration;
	@Override
	public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
		return WebServerInitializedEvent.class.isAssignableFrom(eventType);
	}
	@Override
	public void onApplicationEvent(ApplicationEvent applicationEvent) {
		if (applicationEvent instanceof WebServerInitializedEvent) {
			WebServerInitializedEvent event = (WebServerInitializedEvent) applicationEvent;
			ApplicationContext context = event.getApplicationContext();
			//autoServiceRegistration:ConsulAutoServiceRegistration
			this.autoServiceRegistration.setPortIfNeeded(event.getWebServer().getPort());//设置端口
			this.autoServiceRegistration.start();// 开始注册 
		}
	}
}
  1. ConsulAutoServiceRegistrationListener是监听WebServerInitializedEvent事件的监听器。
  2. 服务注册是通过事件发布机制触发的。其原理参考WebServerInitializedEvent事件
  3. 设置AbstractAutoServiceRegistration中属性port值为当前应用服务的端口。

4.1、AbstractAutoServiceRegistration

public void start() {
	if (!this.running.get()) {
		this.context.publishEvent(
				new InstancePreRegisteredEvent(this, getRegistration()));
		register();//继续注册,调用当前抽象类的子类ConsulAutoServiceRegistration
		if (shouldRegisterManagement()) {
			registerManagement();
		}
		this.context.publishEvent(
				new InstanceRegisteredEvent<>(this, getConfiguration()));
		this.running.compareAndSet(false, true);
	}

}

针对InstancePreRegisteredEvent、InstanceRegisteredEvent事件,应用服务可以实现对应的监听器,在服务注册前后获取相关的注册信息。

4.1.1、尝试设置NewService相关属性

protected ConsulAutoRegistration getRegistration() {
	//registration:ConsulAutoRegistration
	if (this.registration.getService().getPort() == null
			&& this.getPort().get() > 0) {
		this.registration.initializePort(this.getPort().get());
	}
	return this.registration;
}
  1. this.registration.getService():指的是NewService,应用服务实例的抽象。
  2. 如果NewService中端口号没有设置,则初始化为应用服务的端口号。
  3. 如果NewService中端口号没有设置,则初始化用于对应用服务健康检查的相关check信息。

4.1.2、ConsulServiceRegistry

// ConsulAutoServiceRegistration#register
protected void register() {
	if (!this.properties.isRegister()) {//ConsulDiscoveryProperties
		return;
	}
	super.register();//AbstractAutoServiceRegistration#register
}

spring.cloud.consul.discovery.register = false ,该配置控制当前应用服务是否在consul UI界面展示,其应用服务正常加入consul集群提供服务。
spring.cloud.consul.enabled = false,该配置当前应用服务是否加入consul集群。

protected void register() {
	// 3.1 #ConsulServiceRegistry
	this.serviceRegistry.register(getRegistration());
}

4.2、ConsulServiceRegistry

public void register(ConsulRegistration reg) {
	this.client.agentServiceRegister(reg.getService(),this.properties.getAclToken());//
	NewService service = reg.getService();
	if (this.heartbeatProperties.isEnabled() && this.ttlScheduler != null
			&& service.getCheck() != null
			&& service.getCheck().getTtl() != null) {
		this.ttlScheduler.add(reg.getInstanceId());
	}
}
  1. client为ConsulClient。
  2. 注册地址:http://localhost:8500/v1/agent/service/register。

6、Management

如果配置类ConsulDiscoveryProperties的属性healthCheckUrl显式设置,则该种方式获取的端口没有任何意义。

public static boolean shouldRegisterManagement(
		AutoServiceRegistrationProperties autoServiceRegistrationProperties,
		ConsulDiscoveryProperties properties, ApplicationContext context) {
		// registerManagement默认为TRUE
	return autoServiceRegistrationProperties.isRegisterManagement()
			&& getManagementPort(properties, context) != null
			&& ManagementServerPortUtils.isDifferent(context);
}

6.1、getManagementPort

AutoServiceRegistrationProperties:spring.cloud.service-registry.auto-registration

通过Management获取端口号方式:

  1. AutoServiceRegistrationProperties配置类属性registerManagement为TRUE。
  2. ConsulDiscoveryProperties配置类属性managementPort是否存在。
  3. ManagementServerProperties配置类属性port是否存在。
public static Integer getManagementPort(ConsulDiscoveryProperties properties,
		ApplicationContext context) {
	// If an alternate external port is specified, use it instead
	if (properties.getManagementPort() != null) {
		return properties.getManagementPort();
	}
	return ManagementServerPortUtils.getPort(context);
}
public static Integer getPort(BeanFactory beanFactory) {
	ManagementServerProperties properties = beanFactory.getBean(ManagementServerProperties.class);
	return properties.getPort();
}

6.2、ManagementServerPortUtils.isDifferent

public static boolean isDifferent(BeanFactory beanFactory) {
	return get(beanFactory) == ManagementServerPort.DIFFERENT;
}
public static ManagementServerPort get(BeanFactory beanFactory) {
	serverProperties = beanFactory.getBean(ServerProperties.class);//为了获取应用服务的端口
	ManagementServerProperties managementServerProperties = beanFactory.getBean(ManagementServerProperties.class);
	Integer port = managementServerProperties.getPort();
	if (port != null && port < 0) {
		return DISABLE;
	}
	if (!(beanFactory instanceof WebApplicationContext)) {
		// Current context is not a webapp
		return DIFFERENT;
	}
	return ((port == null)
			|| (serverProperties.getPort() == null && port.equals(8080))
			|| (port != 0 && port.equals(serverProperties.getPort())) ? SAME
					: DIFFERENT);
}

7、RibbonConsulAutoConfiguration

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnConsulEnabled
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnProperty(value = "spring.cloud.consul.ribbon.enabled",
		matchIfMissing = true)
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = ConsulRibbonClientConfiguration.class)
public class RibbonConsulAutoConfiguration {}

ConsulRibbonClientConfiguration其实重写了RibbonClientConfiguration中部分默认的负载策略。

相关功能参考孪生文章

public class ConsulRibbonClientConfiguration {
	...
	@Bean
	@ConditionalOnMissingBean
	public ServerList<?> ribbonServerList(IClientConfig config,
			ConsulDiscoveryProperties properties) {
		ConsulServerList serverList = new ConsulServerList(this.client, properties);
		serverList.initWithNiwsConfig(config);
		return serverList;
	}

	@Bean
	@ConditionalOnMissingBean
	public ServerListFilter<Server> ribbonServerListFilter() {
		return new HealthServiceServerListFilter();
	}

	@Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing() {
		return new ConsulPing();
	}

	@Bean
	@ConditionalOnMissingBean
	public ConsulServerIntrospector serverIntrospector() {
		return new ConsulServerIntrospector();
	}

}

分别重写了ribbonServerList、ribbonServerListFilter、ribbonPing等。发现机制利用ribbon的功能实现的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值