Consul初始化过程中涉及三个核心包,分别为spring-cloud-consul-core、spring-cloud-consul-config、spring-cloud-consul-discovery。
spring-cloud-consul-config包涉及两个核心类ConsulConfigAutoConfiguration、ConsulConfigBootstrapConfiguration。
spring-cloud-consul-core包涉及核心类ConsulAutoConfiguration。
spring-cloud-consul-discovery包涉及核心类如下:ConsulConfigServerAutoConfiguration、ConsulServiceRegistryAutoConfiguration等。
该包下核心类ConsulConfigAutoConfiguration主要完成ConfigWatch类初始化。
@Configuration(proxyBeanMethods = false)
@ConditionalOnConsulEnabled
@ConditionalOnProperty(name = "spring.cloud.consul.config.enabled", matchIfMissing = true)
public class ConsulConfigAutoConfiguration {public static final String CONFIG_WATCH_TASK_SCHEDULER_NAME = "configWatchTaskScheduler";@Configuration(proxyBeanMethods = false)@ConditionalOnClass(RefreshEndpoint.class)protected static class ConsulRefreshConfiguration {@Bean@ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled",matchIfMissing = true)public ConfigWatch configWatch(ConsulConfigProperties properties,ConsulPropertySourceLocator locator, ConsulClient consul,@Qualifier(CONFIG_WATCH_TASK_SCHEDULER_NAME) TaskScheduler taskScheduler) {return new ConfigWatch(properties, consul, locator.getContextIndexes(),taskScheduler);}@Bean(name = CONFIG_WATCH_TASK_SCHEDULER_NAME)@ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled",matchIfMissing = true)public TaskScheduler configWatchTaskScheduler() {return new ThreadPoolTaskScheduler();}}
}
ConsulClient是通过配置类ConsulAutoConfiguration实例化完毕的。
ConsulPropertySourceLocator是通过配置类ConsulConfigBootstrapConfiguration实例化完成的。
ConsulConfigProperties中两个核心配置属性:
该类的主要作用是通过定时任务更新配置(KV)。
public class ConfigWatch implements ApplicationEventPublisherAware, SmartLifecycle {@Override public void start() {// Lifecycle的start方法if (this.running.compareAndSet(false, true)) {//taskScheduler:ThreadPoolTaskSchedulerthis.watchFuture = this.taskScheduler.scheduleWithFixedDelay(this::watchConfigKeyValues, this.properties.getWatch().getDelay());}}public void watchConfigKeyValues() {if (this.running.get()) {for (String context : this.consulIndexes.keySet()) {Response> response = this.consul.getKVValues(context,aclToken,new QueryParams(this.properties.getWatch().getWaitTime(),currentIndex));}}}
}
ThreadPoolTaskScheduler相关功能参考
public class ConsulAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic ConsulProperties consulProperties() {return new ConsulProperties();}@Bean@ConditionalOnMissingBeanpublic ConsulClient consulClient(ConsulProperties consulProperties) {final int agentPort = consulProperties.getPort();final String agentHost = !StringUtils.isEmpty(consulProperties.getScheme())? consulProperties.getScheme() + "://" + consulProperties.getHost(): consulProperties.getHost();if (consulProperties.getTls() != null) {ConsulProperties.TLSConfig tls = consulProperties.getTls();TLSConfig tlsConfig = new TLSConfig(tls.getKeyStoreInstanceType(),tls.getCertificatePath(), tls.getCertificatePassword(),tls.getKeyStorePath(), tls.getKeyStorePassword());return new ConsulClient(agentHost, agentPort, tlsConfig);}return new ConsulClient(agentHost, agentPort);}
}
ConsulProperties。@Configuration(proxyBeanMethods = false)
@ConditionalOnConsulEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.enabled",matchIfMissing = true)
@AutoConfigureBefore(ServiceRegistryAutoConfiguration.class)
public class ConsulServiceRegistryAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic ConsulServiceRegistry consulServiceRegistry(ConsulClient consulClient,ConsulDiscoveryProperties properties, HeartbeatProperties heartbeatProperties,@Autowired(required = false) TtlScheduler ttlScheduler) {return new ConsulServiceRegistry(consulClient, properties, ttlScheduler,heartbeatProperties);}@Bean@ConditionalOnMissingBeanpublic HeartbeatProperties heartbeatProperties() {return new HeartbeatProperties();}@Bean@ConditionalOnMissingBean// TODO: Split appropriate values to service-registry for Edgwarepublic ConsulDiscoveryProperties consulDiscoveryProperties(InetUtils inetUtils) {return new ConsulDiscoveryProperties(inetUtils);}}
@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 {@AutowiredAutoServiceRegistrationProperties autoServiceRegistrationProperties;@Bean@ConditionalOnMissingBeanpublic ConsulAutoServiceRegistration consulAutoServiceRegistration(ConsulServiceRegistry registry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties,ConsulAutoRegistration consulRegistration) {return new ConsulAutoServiceRegistration(registry,autoServiceRegistrationProperties, properties, consulRegistration);}@Beanpublic ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener(ConsulAutoServiceRegistration registration) {return new ConsulAutoServiceRegistrationListener(registration);}@Bean@ConditionalOnMissingBeanpublic ConsulAutoRegistration consulRegistration(AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties, ApplicationContext applicationContext,ObjectProvider> registrationCustomizers,ObjectProvider> managementRegistrationCustomizers,HeartbeatProperties heartbeatProperties) {return ConsulAutoRegistration.registration(autoServiceRegistrationProperties,properties, applicationContext, registrationCustomizers.getIfAvailable(),managementRegistrationCustomizers.getIfAvailable(), heartbeatProperties);}@Configuration(proxyBeanMethods = false)@ConditionalOnClass(ServletContext.class)protected static class ConsulServletConfiguration {@Beanpublic ConsulRegistrationCustomizer servletConsulCustomizer(ObjectProvider servletContext) {return new ConsulServletRegistrationCustomizer(servletContext);}}}
public class ConsulAutoRegistration extends ConsulRegistration {/*** Instance ID separator.*/public static final char SEPARATOR = '-';private final AutoServiceRegistrationProperties autoServiceRegistrationProperties;private final ApplicationContext context;private final HeartbeatProperties heartbeatProperties;private final List managementRegistrationCustomizers;public static ConsulAutoRegistration registration(AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties, ApplicationContext context,List registrationCustomizers,List managementRegistrationCustomizers,HeartbeatProperties heartbeatProperties) {NewService service = new NewService();// NewService是consul中对于服务实例的抽象String appName = getAppName(properties, context.getEnvironment());//spring.application.nameservice.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());// we know the port and can set the checksetCheck(service, autoServiceRegistrationProperties, properties, context,heartbeatProperties);}ConsulAutoRegistration registration = new ConsulAutoRegistration(service,autoServiceRegistrationProperties, properties, context,heartbeatProperties, managementRegistrationCustomizers);customize(registrationCustomizers, registration);return registration;}public static void customize(List registrationCustomizers,ConsulAutoRegistration registration) {if (registrationCustomizers != null) {for (ConsulRegistrationCustomizer customizer : registrationCustomizers) {customizer.customize(registration);}}}public static void setCheck(NewService service,AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties, ApplicationContext context,HeartbeatProperties heartbeatProperties) {if (properties.isRegisterHealthCheck() && service.getCheck() == null) {Integer checkPort;if (shouldRegisterManagement(autoServiceRegistrationProperties, properties,context)) {checkPort = getManagementPort(properties, context);}else {checkPort = service.getPort();}service.setCheck(createCheck(checkPort, heartbeatProperties, properties));}}public static ConsulAutoRegistration managementRegistration(AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties, ApplicationContext context,List managementRegistrationCustomizers,HeartbeatProperties heartbeatProperties) {NewService management = new NewService();management.setId(getManagementServiceId(properties, context));management.setAddress(properties.getHostname());management.setName(getManagementServiceName(properties, context.getEnvironment()));management.setPort(getManagementPort(properties, context));management.setTags(properties.getManagementTags());if (properties.isRegisterHealthCheck()) {management.setCheck(createCheck(getManagementPort(properties, context),heartbeatProperties, properties));}ConsulAutoRegistration registration = new ConsulAutoRegistration(management,autoServiceRegistrationProperties, properties, context,heartbeatProperties, managementRegistrationCustomizers);managementCustomize(managementRegistrationCustomizers, registration);return registration;}public static void managementCustomize(List registrationCustomizers,ConsulAutoRegistration registration) {if (registrationCustomizers != null) {for (ConsulManagementRegistrationCustomizer customizer : registrationCustomizers) {customizer.customize(registration);}}}public static String getInstanceId(ConsulDiscoveryProperties properties,ApplicationContext context) {if (!StringUtils.hasText(properties.getInstanceId())) {return normalizeForDns(IdUtils.getDefaultInstanceId(context.getEnvironment(),properties.isIncludeHostnameInInstanceId()));}return normalizeForDns(properties.getInstanceId());}public static String normalizeForDns(String s) {...StringBuilder normalized = new StringBuilder();Character prev = null;for (char curr : s.toCharArray()) {Character toAppend = null;if (Character.isLetterOrDigit(curr)) {toAppend = curr;}else if (prev == null || !(prev == SEPARATOR)) {toAppend = SEPARATOR;}if (toAppend != null) {normalized.append(toAppend);prev = toAppend;}}return normalized.toString();}public static List createTags(ConsulDiscoveryProperties properties) {List tags = new LinkedList<>(properties.getTags());if (!StringUtils.isEmpty(properties.getInstanceZone())) {tags.add(properties.getDefaultZoneMetadataName() + "="+ properties.getInstanceZone());}if (!StringUtils.isEmpty(properties.getInstanceGroup())) {tags.add("group=" + properties.getInstanceGroup());}tags.add("secure="+ Boolean.toString(properties.getScheme().equalsIgnoreCase("https")));return tags;}public static NewService.Check createCheck(Integer port,HeartbeatProperties ttlConfig, ConsulDiscoveryProperties properties) {NewService.Check check = new NewService.Check();if (StringUtils.hasText(properties.getHealthCheckCriticalTimeout())) {check.setDeregisterCriticalServiceAfter(properties.getHealthCheckCriticalTimeout());}if (ttlConfig.isEnabled()) {check.setTtl(ttlConfig.getTtl());return check;}if (properties.getHealthCheckUrl() != null) {check.setHttp(properties.getHealthCheckUrl());}else {check.setHttp(String.format("%s://%s:%s%s", properties.getScheme(),properties.getHostname(), port, properties.getHealthCheckPath()));}check.setHeader(properties.getHealthCheckHeaders());check.setInterval(properties.getHealthCheckInterval());check.setTimeout(properties.getHealthCheckTimeout());check.setTlsSkipVerify(properties.getHealthCheckTlsSkipVerify());return check;}public static String getAppName(ConsulDiscoveryProperties properties,Environment env) {final String appName = properties.getServiceName();if (StringUtils.hasText(appName)) {return appName;}return env.getProperty("spring.application.name", "application");}public static boolean shouldRegisterManagement(AutoServiceRegistrationProperties autoServiceRegistrationProperties,ConsulDiscoveryProperties properties, ApplicationContext context) {return autoServiceRegistrationProperties.isRegisterManagement()&& getManagementPort(properties, context) != null&& ManagementServerPortUtils.isDifferent(context);}public static String getManagementServiceId(ConsulDiscoveryProperties properties,ApplicationContext context) {final String instanceId = properties.getInstanceId();if (StringUtils.hasText(instanceId)) {return normalizeForDns(instanceId + SEPARATOR + properties.getManagementSuffix());}return normalizeForDns(IdUtils.getDefaultInstanceId(context.getEnvironment(), false)) + SEPARATOR+ properties.getManagementSuffix();}public static String getManagementServiceName(ConsulDiscoveryProperties properties,Environment env) {final String appName = properties.getServiceName();if (StringUtils.hasText(appName)) {return normalizeForDns(appName + SEPARATOR + properties.getManagementSuffix());}return normalizeForDns(getAppName(properties, env)) + SEPARATOR+ properties.getManagementSuffix();}public static Integer getManagementPort(ConsulDiscoveryProperties properties,ApplicationContext context) {// If an alternate external port is specified, use it insteadif (properties.getManagementPort() != null) {return properties.getManagementPort();}return ManagementServerPortUtils.getPort(context);}public void initializePort(int knownPort) {if (getService().getPort() == null) {// not set by propertiesgetService().setPort(knownPort);}// we might not have a port until now, so this is the earliest we// can create a checksetCheck(getService(), this.autoServiceRegistrationProperties, getProperties(),this.context, this.heartbeatProperties);}public ConsulAutoRegistration managementRegistration() {return managementRegistration(this.autoServiceRegistrationProperties,getProperties(), this.context, this.managementRegistrationCustomizers,this.heartbeatProperties);}}
public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener {// ConsulAutoServiceRegistrationprivate final ConsulAutoServiceRegistration autoServiceRegistration;public ConsulAutoServiceRegistrationListener(ConsulAutoServiceRegistration autoServiceRegistration) {this.autoServiceRegistration = autoServiceRegistration;}@Overridepublic boolean supportsEventType(Class extends ApplicationEvent> eventType) {return WebServerInitializedEvent.class.isAssignableFrom(eventType);}@Overridepublic boolean supportsSourceType(Class> sourceType) {return true;}@Overridepublic void onApplicationEvent(ApplicationEvent applicationEvent) {if (applicationEvent instanceof WebServerInitializedEvent) {WebServerInitializedEvent event = (WebServerInitializedEvent) applicationEvent;ApplicationContext context = event.getApplicationContext();this.autoServiceRegistration.setPortIfNeeded(event.getWebServer().getPort());this.autoServiceRegistration.start();// 开始注册 }}
}
事件发布机制触发的。其原理参考WebServerInitializedEvent事件。public void start() {// only initialize if nonSecurePort is greater than 0 and it isn't already running// because of containerPortInitializer belowif (!this.running.get()) {this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));register();//继续注册if (shouldRegisterManagement()) {registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));this.running.compareAndSet(false, true);}}
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());}
}
上一篇:如何看待一个爱撒谎的男人
下一篇:洗牌舞为什么叫鬼舞?