I. Engineering structure

Second, the UML

  • Registration: a markup interface that extends ServiceInstance to represent an abstract ServiceInstance and provides getters and setters for serviceId, host, port, URI, protocol, and metadata. Consul is to his implementation ConsulRegistration. Consul autoregistration is Consul’s extension of Consul’s own service registration. Consul’s own service instance is NewService, Consul’s own metadata, Consul’s own health Check parameter Settings, and so on.

  • ServiceRegistry: Provides getters and setters for service registration, service deregistration, and service status for Regisration. Consulservice eregistry is his implementation.

  • AutoServiceRegistration: a marker interface, it is the abstract implementation of AbstractAutoServiceRegistration, concrete implementation is ConsulAutoServiceRegistration. AbstractAutoServiceRegistration class is provided by the spring – cloud – Commons. Its start method provides automatic service Registration capability, how to obtain configuration, Registration instances by subclass implementation.

  • SmartApplicationListener ConsulAutoServiceRegistrationListener: implementation, using Spring event mechanism of extension points, trigger automatic registration service
  • ConsulRegistrationCustomizer: Consul ConsulRegistration provide extension points. Provide the user with an interface to extend ConsulRegistration after the construction is complete
public interface ConsulRegistrationCustomizer {
	void customize(ConsulRegistration registration);
}
Copy the code
  • ConsulServiceRegistryAutoConfiguration: ConsulServiceRegistry configuration class
  • ConsulAutoServiceRegistrationAutoConfiguration: ConsulAutoRegistration and ConsulServiceAutoRegistration configuration class

Three, start with configuration

  • spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration,\
org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration\
...
Copy the code

3.1 ConsulServiceRegistryAutoConfiguration

  • Injection conditions
/ / 1, spring. Cloud. Consul. Enabled matchIfMissing = true / / 2, ConsulClient. @ ConditionalOnConsulEnabled / / class exists 1, spring. Cloud. Service - registry. Enabled matchIfMissing = true / / 2, spring. Cloud. Consul. Service - registry. Enabled matchIfMissing = true @Conditional(ConsulServiceRegistryAutoConfiguration.OnConsulRegistrationEnabledCondition.class) @AutoConfigureBefore(ServiceRegistryAutoConfiguration.class) public class ConsulServiceRegistryAutoConfiguration {Copy the code
  • ServiceRegistryAutoConfiguration: spring — cloud – common, check to the health of the service registry
public class ServiceRegistryAutoConfiguration { @ConditionalOnBean(ServiceRegistry.class) @ConditionalOnClass(Endpoint.class) protected class ServiceRegistryEndpointConfiguration { @Autowired(required = false) private Registration registration; @Bean @ConditionalOnAvailableEndpoint public ServiceRegistryEndpoint serviceRegistryEndpoint( ServiceRegistry serviceRegistry) { ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint( serviceRegistry); endpoint.setRegistration(this.registration); return endpoint; }}}Copy the code
  • ConsulServiceRegistry: Directly operate ConsulClient and provide service registration functions
@Bean
	@ConditionalOnMissingBean
	public ConsulServiceRegistry consulServiceRegistry(ConsulClient consulClient,
			ConsulDiscoveryProperties properties, HeartbeatProperties heartbeatProperties,
			@Autowired(required = false) TtlScheduler ttlScheduler) {
		return new ConsulServiceRegistry(consulClient, properties, ttlScheduler,
				heartbeatProperties);
	}
Copy the code
  • HeartbeatProperties: configuration class of heartbeat detection mode for health check
@Bean
	@ConditionalOnMissingBean
	public HeartbeatProperties heartbeatProperties() {
		return new HeartbeatProperties();
	}
Copy the code
  • ConsulDiscoveryProperties: service registration and discovery of related configuration (service registration and discovery configuration mixing together, official comments mean consider separate registration and discovery of configuration management is more suitable)
@Bean
	@ConditionalOnMissingBean
	// TODO: Split appropriate values to service-registry for Edgware
	public ConsulDiscoveryProperties consulDiscoveryProperties(InetUtils inetUtils) {
		return new ConsulDiscoveryProperties(inetUtils);
	}
Copy the code

3.2 ConsulAutoServiceRegistrationAutoConfiguration

  • Effective condition
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnMissingBean( type = "Org. Springframework. Cloud. Consul. Discovery. ConsulLifecycle") / / 1, spring. Cloud. Consul. Enabled matchIfMissing = true / / 2, ConsulClient. Class is @ ConditionalOnConsulEnabled / / 1, spring. Cloud. Service - registry. Auto - registration. Enabled MatchIfMissing = true / / 2, spring. Cloud. Consul. Service - registry. Auto - registration. Enabled matchIfMissing = true / / 3, spring. Cloud. Service - registry. Enabled matchIfMissing = true / / 4, spring. Cloud. Consul. Service - registry. Enabled matchIfMissing = true @Conditional(ConsulAutoServiceRegistrationAutoConfiguration.OnConsulRegistrationEnabledCondition.class) @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, ConsulServiceRegistryAutoConfiguration.class }) public class ConsulAutoServiceRegistrationAutoConfiguration {Copy the code
  • ConsulAutoRegistration: Represents the current service instance
@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); }Copy the code
  • , including the AbstractAutoServiceRegistration ConsulAutoServiceRegistration: service registry function
@Bean
@ConditionalOnMissingBean
public ConsulAutoServiceRegistration consulAutoServiceRegistration(
        ConsulServiceRegistry registry,
        AutoServiceRegistrationProperties autoServiceRegistrationProperties,
        ConsulDiscoveryProperties properties,
        ConsulAutoRegistration consulRegistration) {
    return new ConsulAutoServiceRegistration(registry,
            autoServiceRegistrationProperties, properties, consulRegistration);
}
Copy the code
  • The entrance to the ConsulAutoServiceRegistrationListener: service automatically register
@Bean
public ConsulAutoServiceRegistrationListener consulAutoServiceRegistrationListener(
        ConsulAutoServiceRegistration registration) {
    return new ConsulAutoServiceRegistrationListener(registration);
}
Copy the code

Fourth, ConsulAutoServiceRegistrationListener when performing service registration, who by operating the service registry

  • ConsulAutoServiceRegistrationListener as service registry entry, using a Spring which extension points?

The Event is found that in the debug ConsulAutoServiceRegistrationListener, attention after the Servlet container to start the trigger, Trigger the entry is: org. Springframework. Boot. Web. Reactive. Context. WebServerManager# start

void start() { this.handler.initializeHandler(); // Tomcat starts this.webserver.start (); / / release ReactiveWebServerInitializedEvent event, This event is inherited WebServerInitializedEvent enclosing applicationContext. PublishEvent (new ReactiveWebServerInitializedEvent(this.webServer, this.applicationContext)); }Copy the code

And ConsulAutoServiceRegistrationListener to monitor events is WebServerInitializedEvent, triggering the service registration process.

public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener { // Listening WebServerInitializedEvent event @ Override public Boolean supportsEventType (Class <? extends ApplicationEvent> eventType) { return WebServerInitializedEvent.class.isAssignableFrom(eventType); }Copy the code
  • Through whom do you register for operating services?

ConsulAutoServiceRegistration implements AbstractAutoServiceRegistration, mainly provides service registration process on the specific implementation, ConsulService registration apis are a matter for consulService gistry.

public class ConsulAutoServiceRegistrationListener implements SmartApplicationListener { private final ConsulAutoServiceRegistration autoServiceRegistration; @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { if (applicationEvent instanceof WebServerInitializedEvent) { WebServerInitializedEvent event = (WebServerInitializedEvent) applicationEvent; / / by WebServerInitializedEvent can access to the WebServer instance, And then get to the port this. AutoServiceRegistration. SetPortIfNeeded (event. GetWebServer (.) getPort ()); / / execution service registration processes. AutoServiceRegistration. Start (); }}}Copy the code

Five, the service registration processes: ConsulAutoServiceRegistration

  • ConsulAutoServiceRegistration start method is only called the abstract parent class start method, abstract parent class start method belongs to a template method, a lot of things are realized by subclasses
    • Also note that the previously mentioned springRetry interceptor provided by the Core module is used here. If we introduce the Spring-Retry framework, we can perform service registration retries according to the configuration conditions. Juejin. Cn/post / 687154…
@Override @Retryable(interceptor = "consulRetryInterceptor") public void start() { // 1. Judge ConsulAutoServiceRegistration. IsEnabled / / 2. Release InstancePreRegisteredEvent event / / 3. Call ConsulAutoServiceRegistration. Register / / 4. Release InstanceRegisteredEvent event // 5. Running =true super.start(); }Copy the code
  • AbstractAutoServiceRegistration. Start: main control the process of service registry, set aside all the extension point, don’t have to consider these things, let subclasses subclass as long as responsible for the specific service registry
Public void the start () {/ / 1. Subclasses implementation: judge ConsulAutoServiceRegistration isEnabled if (! isEnabled()) { return; } if (! This.running.get ()) {// 2. Release events InstancePreRegisteredEvent enclosing context. PublishEvent (new InstancePreRegisteredEvent (this, getRegistration ())); / / 3. Subclasses: how to sign up for a service call ConsulAutoServiceRegistration. Register register (); // 4. Release events InstanceRegisteredEvent enclosing context. PublishEvent (new InstanceRegisteredEvent < > (this, getConfiguration ())); / / 5. An abstract class control, set out service already registered the this.running.com pareAndSet (false, true); }}Copy the code
  • Specific see ConsulAutoServiceRegistration. The logic of the register, how to implement the service registration
protected void register() { // 1. Judge spring. Cloud. Consul. Discovery. Register the if (! this.properties.isRegister()) { log.debug("Registration disabled."); return; Super.register (); // Call ConsulAutoRegistration super.register(); }Copy the code
  • Subclass is only auxiliary registered judge whether to allow the configuration, the realization of ultimate or superclass AbstractAutoServiceRegistration register method, and the realization of the parent class, It is simply a matter of executing the register method with injected consulService eregistry. ConsulAutoRegistration a service instance containing host, port, and other required information is referred to in Consul.
	protected void register() {
		this.serviceRegistry.register(getRegistration());
	}
Copy the code
  • ConsulServiceRegistry. Register, is mainly responsible for operating ConsulAPI actually perform the service registry
@Override public void register(ConsulRegistration reg) { try { // 1. http://localhost:8500/v1/agent/service/register Register a service instance with Consul // Packet content // {" ID ":" testConsulApp - 8080 ", "Name" : "testConsulApp", "Tags" : [" secure \ u003dfalse] ", "Address" : "192.168.0.105", "Meta" : {}, "Port ": 8080," Check ": {" Interval" : "10 s", "HTTP" : "http://192.168.0.105:8080/actuator/health", "Header" : {}}} this.client.agentServiceRegister(reg.getService(), this.properties.getAclToken()); NewService service = reg.getService(); / / 2. If the health check is the heart way, is to submit a timing task, continue to consul agent sends a heartbeat if (this. HeartbeatProperties. IsEnabled () && enclosing ttlScheduler! = null && service.getCheck() ! = null && service.getCheck().getTtl() ! = null) { this.ttlScheduler.add(reg.getInstanceId()); } } catch (ConsulException e) { // 3. If it is a fail fast, the exception is thrown directly, or eat exception if (this. The properties. IsFailFast ()) {ReflectionUtils. RethrowRuntimeException (e); }}}Copy the code

Six, summarized

  • What are the functions of Registration, ServiceRegistry, etc.
  • The SpringCloudConsul service registry takes advantage of the Spring container event extension point to perform a service registry
  • SpringCloudConsul service after the Servlet container is the time of registration, release WebServerInitializedEvent events, and can get through this event such as Tomcat container instance, to obtain properties such as port
  • AbstractAutoServiceRegistration control service registration processes, extension points are set aside, let subclasses ConsulAutoServiceRegistration attentively service registry
  • / v1 / agent/service/register is consul service registry API