Preface
When we use the @DiscoveryClient annotation, will we have the following question: Why does it perform the operation of registering a service? Shouldn't it be used as service discovery? Let’s explore its source code in depth.
1. Springframework's LifeCycle interface
To understand this issue, we need to understand this important interface:
/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.context;/** * A common interface defining methods for start/stop lifecycle control. * The typical use case for this is to control asynchronous processing. * <b>NOTE: This interface does not imply specific auto-startup semantics. * Consider implementing {@link SmartLifecycle} for that purpose.</b> * * <p>Can be implemented by both components (typically a Spring bean defined in a * Spring context) and containers (typically a Spring {@link ApplicationContext} * itself). Containers will propagate start/stop signals to all components that * apply within each container, eg for a stop/restart scenario at runtime. * * <p>Can be used for direct invocations or for management operations via JMX. * In the latter case, the {@link org.springframework.jmx.export.MBeanExporter} * will typically be defined with an * {@link org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler}, * restricting the visibility of activity-controlled components to the Lifecycle * interface. * * <p>Note that the Lifecycle interface is only supported on <b>top-level singleton * beans</b>. On any other component, the Lifecycle interface will remain undetected * and hence ignored. Also, note that the extended {@link SmartLifecycle} interface * provides integration with the application context's startup and shutdown phases. * * @author Juergen Hoeller * @since 2.0 * @see SmartLifecycle * @see ConfigurableApplicationContext * @see org.springframework.jms.listener.AbstractMessageListenerContainer * @see org.springframework.scheduling.quartz.SchedulerFactoryBean */public interface Lifecycle { /** * Start this component. * <p>Should not throw an exception if the component is already running. * <p>In the case of a container, this will propagate the start signal to all * components that apply. * @see SmartLifecycle#isAutoStartup() */ void start(); /** * Stop this component, typically in a synchronous fashion, such that the component is * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle} * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary. * <p>Note that this stop notification is not guaranteed to come before destruction: On * regular shutdown, {@code Lifecycle} beans will first receive a stop notification before * the general destruction callbacks are being propagated; however, on hot refresh during a * context's lifetime or on aborted refresh attempts, only destroy methods will be called. * <p>Should not throw an exception if the component isn't started yet. * <p>In the case of a container, this will propagate the stop signal to all components * that apply. * @see SmartLifecycle#stop(Runnable) * @see org.springframework.beans.factory.DisposableBean#destroy() */ void stop(); /** * Check whether this component is currently running. * <p>In the case of a container, this will return {@code true} only if <i>all</i> * components that apply are currently running. * @return whether the component is currently running */ boolean isRunning();}This interface defines the start/stop lifecycle control method. When the spring ioc container starts or stops, a start or stop signal will be sent to each component, so we can do what we want in the corresponding method. We can find through the class diagram that we commonly use ClasspathXmlApplicationContext class implements this interface
Let’s briefly demonstrate the case and create the class MyLifeCycle:
package org.hzgj.spring.study.context;import org.springframework.context.SmartLifecycle;public class MyLifeCycle implements SmartLifecycle { @Override public void start() { System.out.println("MyLifeCycle start ...."); } @Override public void stop() { System.out.println("MyLifeCycle stop ....."); } @Override public boolean isRunning() { return false; } @Override public boolean isAutoStartup() { return true; } @Override public void stop(Runnable callback) { } @Override public int getPhase() { System.out.println("phase"); return 10; }}Here we inherit SmartLifeCycle. The interface inherits LifeCycle. The isRunning method is used to detect whether the current component is in the running state. Note that it can only run when the return value isRunning is false.
We configure MyLifeCycle into the spring configuration file, and run through ClassPathXmlApplicationContext to get the following results:
In addition, the getPhase method here is to define the stage value (it can be understood as priority. The smaller the value, the more the corresponding LifeCycle is executed first)
2. DiscoveryClient source code research
@EnableDiscoveyClient
/* * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governance permissions and * limitations under the License. */package org.springframework.cloud.client.discovery;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.context.annotation.Import;/** * Annotation to enable a DiscoveryClient implementation. * @author Spencer Gibb */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(EnableDiscoveryClientImportSelector.class)public @interface EnableDiscoveryClient { /** * If true, the ServiceRegistry will automatically register the local server. */ boolean autoRegister() default true;} Please note that @Import(EnableDiscoveryClientImportSelector.class) We can refer to this class:
/* * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.cloud.client.discovery;import org.springframework.boot.bind.RelaxedPropertyResolver;import org.springframework.cloud.commons.util.SpringFactoryImportSelector;import org.springframework.core.Ordered;import org.springframework.core.annotation.AnnotationAttributes;import org.springframework.core.annotation.Order;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.Environment;import org.springframework.core.env.MapPropertySource;import org.springframework.core.type.AnnotationMetadata;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedHashMap;import java.util.List;/** * @author Spencer Gibb */@Order(Ordered.LOWEST_PRECEDENCE - 100)public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> { @Override public String[] selectImports(AnnotationMetadata metadata) { String[] imports = super.selectImports(metadata); AnnotationAttributes attributes = AnnotationAttributes.fromMap( metadata.getAnnotationAttributes(getAnnotationClass().getName(), true)); boolean autoRegister = attributes.getBoolean("autoRegister"); if (autoRegister) { List<String> importsList = new ArrayList<>(Arrays.asList(imports)); importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration"); imports = importsList.toArray(new String[0]); } else { Environment env = getEnvironment(); if(ConfigurableEnvironment.class.isInstance(env)) { ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env; LinkedHashMap<String, Object> map = new LinkedHashMap<>(); map.put("spring.cloud.service-registry.auto-registration.enabled", false); MapPropertySource propertySource = new MapPropertySource( "springCloudDiscoveryClient", map); configEnv.getPropertySources().addLast(propertySource); } } return imports; } @Override protected boolean isEnabled() { return new RelaxedPropertyResolver(getEnvironment()).getProperty( "spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE); } @Override protected boolean hasDefaultFactory() { return true; }} The method of rewriting this class comes from the interface ImportSelector. We can track the class according to the code under if(autoRegister) : org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration . Let's take a look at the structural diagram:
We can know that this class implements the Lifecycle interface, so let's take a look at the start method, which is in its parent class AbstractDiscoveryLifecycle:
/* * Copyright 2013-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.cloud.client.discovery;import java.util.concurrent.atomic.AtomicBoolean;import java.util.concurrent.atomic.AtomicInteger;import javax.annotation.PreDestroy;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.BeansException;import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;import org.springframework.cloud.client.serviceregistry.ServiceRegistry;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.ApplicationListener;import org.springframework.core.env.Environment;/** * Lifecycle methods that may be useful and common to various DiscoveryClient implementations. * * @deprecated use {@link org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration} instead. This class will be removed in the next release train. * * @author Spencer Gibb */@Deprecatedpublic abstract class AbstractDiscoveryLifecycle implements DiscoveryLifecycle, ApplicationContextAware, ApplicationListener<EmbeddedServletContainerInitializedEvent> { private static final Log logger = LogFactory.getLog(AbstractDiscoveryLifecycle.class); private boolean autoStartup = true; private AtomicBoolean running = new AtomicBoolean(false); private int order = 0; private ApplicationContext context; private Environment environment; private AtomicInteger port = new AtomicInteger(0); protected ApplicationContext getContext() { return context; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; this.environment = this.context.getEnvironment(); } @Deprecated protected Environment getEnvironment() { return environment; } @Deprecated protected AtomicInteger getPort() { return port; } @Override public boolean isAutoStartup() { return this.autoStartup; } @Override public void stop(Runnable callback) { try { stop(); } catch (Exception e) { logger.error("A problem occurred attempting to stop discovery lifecycle", e); } callback.run(); } @Override public void start() { if (!isEnabled()) { if (logger.isDebugEnabled()) { logger.debug("Discovery Lifecycle disabled. Not starting"); } return; } // only set the port if the nonSecurePort is 0 and this.port != 0 if (this.port.get() != 0 && getConfiguredPort() == 0) { setConfiguredPort(this.port.get()); } // only initialize if nonSecurePort is greater than 0 and it isn't already running // because of containerPortInitializer below if (!this.running.get() && getConfiguredPort() > 0) { register(); if (shouldRegisterManagement()) { registerManagement(); } this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration())); this.running.compareAndSet(false, true); } } @Deprecated protected abstract int getConfiguredPort(); @Deprecated protected abstract void setConfiguredPort(int port); /** * @return if the management service should be registered with the {@link ServiceRegistry} */ protected boolean shouldRegisterManagement() { return getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context); } /** * @return the object used to configure the registration */ @Deprecated protected abstract Object getConfiguration(); /** * Register the local service with the DiscoveryClient */ protected abstract void register(); /** * Register the local management service with the DiscoveryClient */ protected void registerManagement() { } /** * De-register the local service with the DiscoveryClient */ protected abstract void deregister(); /** * De-register the local management service with the DiscoveryClient */ protected void deregisterManagement() { } /** * @return true, if the {@link DiscoveryLifecycle} is enabled */ protected abstract boolean isEnabled(); /** * @return the serviceId of the Management Service */ @Deprecated protected String getManagementServiceId() { // TODO: configurable management suffix return this.context.getId() + ":management"; } /** * @return the service name of the Management Service */ @Deprecated protected String getManagementServiceName() { // TODO: configurable management suffix return getAppName() + ":management"; } /** * @return the management server port */ @Deprecated protected Integer getManagementPort() { return ManagementServerPortUtils.getPort(this.context); } /** * @return the app name, currently the spring.application.name property */ @Deprecated protected String getAppName() { return this.environment.getProperty("spring.application.name", "application"); } @Override public void stop() { if (this.running.compareAndSet(true, false) && isEnabled()) { deregister(); if (shouldRegisterManagement()) { deregisterManagement(); } } } @PreDestroy public void destroy() { stop(); } @Override public boolean isRunning() { return this.running.get(); } protected AtomicBoolean getRunning() { return running; } @Override public int getOrder() { return this.order; } @Override public int getPhase() { return 0; } @Override @Deprecated public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) { // TODO: take SSL into account // Don't register the management port as THE port if (!"management".equals(event.getApplicationContext().getNamespace())) { this.port.compareAndSet(0, event.getEmbeddedServletContainer().getPort()); this.start(); } }}Note that there is a piece of this code in the start method:
if (!this.running.get() && getConfiguredPort() > 0) { register(); if (shouldRegisterManagement()) { registerManagement(); } this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration())); this.running.compareAndSet(false, true); } Please note register() method is an abstract method in this class. So let's look back at the code in the AbstractAutoServiceRegistration class, and I will only post the key parts here:
//..... protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) { this.serviceRegistry = serviceRegistry; this.properties = properties; }//....../** * Register the local service with the {@link ServiceRegistry} */ @Override protected void register() { this.serviceRegistry.register(getRegistration()); }We can find that a ServiceRegistry type is passed in the constructor, which is an interface SpringCloud provides us with for service registration. Here EurekaServiceRegistry implements this interface:
/* * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */package org.springframework.cloud.netflix.eureka.serviceregistry;import java.util.HashMap;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.cloud.client.serviceregistry.ServiceRegistry;import com.netflix.appinfo.InstanceInfo;/** * @author Spencer Gibb */public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration> { private static final Log log = LogFactory.getLog(EurekaServiceRegistry.class); @Override public void register(EurekaRegistration reg) { maybeInitializeClient(reg); if (log.isInfoEnabled()) { log.info("Registering application " + reg.getInstanceConfig().getAppname() + " with eureka with status " + reg.getInstanceConfig().getInitialStatus()); } reg.getApplicationInfoManager() .setInstanceStatus(reg.getInstanceConfig().getInitialStatus()); if (reg.getHealthCheckHandler() != null) { reg.getEurekaClient().registerHealthCheck(reg.getHealthCheckHandler()); } } private void maybeInitializeClient(EurekaRegistration reg) { // force initialization of possible scoped proxies reg.getApplicationInfoManager().getInfo(); reg.getEurekaClient().getApplications(); } @Override public void deregister(EurekaRegistration reg) { if (reg.getApplicationInfoManager().getInfo() != null) { if (log.isInfoEnabled()) { log.info("Unregistering application " + reg.getInstanceConfig().getAppname() + " with eureka with status DOWN"); } reg.getApplicationInfoManager().setInstanceStatus(InstanceInfo.InstanceStatus.DOWN); //shutdown of eureka client should happen with EurekaRegistration.close() //auto registration will create a bean which will be properly distributed //manual registrations will need to call close() } } @Override public void setStatus(EurekaRegistration registration, String status) { InstanceInfo info = registration.getApplicationInfoManager().getInfo(); //TODO: howto deal with delete properly? if ("CANCEL_OVERRIDE".equalsIgnoreCase(status)) { registration.getEurekaClient().cancelOverrideStatus(info); return; } //TODO: howto deal with status types across discovery systems? InstanceInfo.InstanceStatus newStatus = InstanceInfo.InstanceStatus.toEnum(status); registration.getEurekaClient().setStatus(newStatus, info); } @Override public Object getStatus(EurekaRegistration registration) { HashMap<String, Object> status = new HashMap<>(); InstanceInfo info = registration.getApplicationInfoManager().getInfo(); status.put("status", info.getStatus().toString()); status.put("overriddenStatus", info.getOverriddenStatus().toString()); return status; } public void close() { }}So we can summarize the following points:
1. Using @DiscoveryClient to register the service uses the LifeCycle mechanism, and register() method of ServiceRegistry will be executed when the container is started.
2. Using @DiscoveryClient is more flexible than @EnableEurekaClient and @EnableEurekaServer, because it blocks the implementation of service registration, and we can even customize the registration center.
3. This will also automatically search for the implementation of the DiscoveryClient interface for service discovery.
3. Discoveryclient practical redis registration center
Below we implement a requirement based on redis as the registration center to understand Discoveryclient. By the way, let’s understand the important interfaces of Springcloud: ServiceRegistry, ServiceInstance. Before this, we will add support for redis:
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis'
1. Implement the Registration interface
package com.hzgj.lyrk.member;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.client.serviceregistry.Registration;import org.springframework.stereotype.Component;import java.net.InetAddress;import java.net.NetworkInterface;import java.net.URI;import java.util.Enumeration;import java.util.Map;@Componentpublic class RedisRegistration implements Registration { @Value("${server.port}") private Integer port; @Value("${spring.application.name}") private String applicationName; private String host; public void setHost(String host) { this.host = host; } public void setPort(Integer port) { this.port = port; } public void setApplicationName(String applicationName) { this.applicationName = applicationName; } @Override public String getServiceId() { return applicationName + ":" + getHost() + ":" + getPort(); } @Override public String getHost() { try { if (host == null) return getLocalHostLANAddress().getHostAddress(); else return host; } catch (Exception e) { e.printStackTrace(); } return null; } @Override public int getPort() { return port; } @Override public boolean isSecure() { return false; } @Override public URI getUri() { return null; } @Override public Map<String, String> getMetadata() { return null; } public String getServiceName() { return this.applicationName; } public InetAddress getLocalHostLANAddress() throws Exception { try { InetAddress candidateAddress = null; // traverse all network interfaces for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { NetworkInterface iface = (NetworkInterface) ifaces.nextElement(); // traverse the IP under all interfaces for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { InetAddress inetAddr = (InetAddress) inetAddrs.nextElement(); if (!inetAddr.isLoopbackAddress()) {// Exclude loopback type address if (inetAddr.isSiteLocalAddress()) { // If it is a site-local address, it is return inetAddr; } else if (candidateAddress == null) { // The address of the site-local type has not been found, first record the candidate address candidateAddress = inetAddr; } } } } } if (candidateAddress != null) { return candidateAddress; } // If no non-loopback address is found, you can only use the most selected solution. InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); return jdkSuppliedAddress; } catch (Exception e) { e.printStackTrace(); } return null; }}This interface inherits ServiceIntance, so the main function of this interface is to define the specifications of a service instance, such as what is its serviceId, what is the port number, etc.
2. Implement the interface of ServiceRegistry
package com.hzgj.lyrk.member;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.serviceregistry.ServiceRegistry;import org.springframework.data.redis.core.StringRedisTemplate;public class RedisServiceRegistry implements ServiceRegistry<RedisRegistration> { @Autowired private StringRedisTemplate redisTemplate; @Override public void register(RedisRegistration registration) { String serviceId = registration.getServiceId(); redisTemplate.opsForList().leftPush(serviceId, registration.getHost() + ":" + registration.getPort()); } @Override public void deregister(RedisRegistration registration) { redisTemplate.opsForList().remove(registration.getServiceId(), 1, registration.getHost() + ":" + registration.getPort()); } @Override public void close() { //redisTemplate.d System.out.println("closed..."); } @Override public void setStatus(RedisRegistration registration, String status) { } @Override public <T> T getStatus(RedisRegistration registration) { return null; }}The main function of this interface is to define how to register, cancel service, set and obtain service status, etc.
3. Inherit AbstractAutoServiceRegistration abstract class
package com.hzgj.lyrk.member;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;import org.springframework.cloud.client.serviceregistry.ServiceRegistry;public class RedisAutoServiceRegistration extends AbstractAutoServiceRegistration<RedisRegistration> { @Autowired private RedisRegistration redisRegistration; protected RedisAutoServiceRegistration(ServiceRegistry<RedisRegistration> serviceRegistry, AutoServiceRegistrationProperties properties) { super(serviceRegistry, properties); // serviceRegistry.register(getRegistration()); } @Override protected int getConfiguredPort() { return redisRegistration.getPort(); } @Override protected void setConfiguredPort(int port) { } @Override protected Object getConfiguration() { return null; } @Override protected boolean isEnabled() { return true; } @Override protected RedisRegistration getRegistration() { return redisRegistration; } @Override protected RedisRegistration getManagementRegistration() { return null; }}4. Define the implementation class of DiscoveryClient RedisDiscoveryClient
package com.hzgj.lyrk.member;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.data.redis.core.StringRedisTemplate;import java.util.ArrayList;import java.util.List;import java.util.function.Function;import java.util.stream.Collectors;public class RedisDiscoveryClient implements DiscoveryClient { @Autowired private StringRedisTemplate redisTemplate; @Override public String description() { return "Service Discovery in Redis Registration Center"; } @Override public ServiceInstance getLocalServiceInstance() { return null; } @Override public List<ServiceInstance> getInstances(String serviceId) { return redisTemplate.opsForList().range(serviceId, 0, -1). parallelStream().map((Function<String, ServiceInstance>) s -> { RedisRegistration redisRegistration = new RedisRegistration(); redisRegistration.setApplicationName(serviceId); String hostName = StringUtils.split(s, ":")[0]; String port = StringUtils.split(s, ":")[1]; redisRegistration.setHost(hostName); redisRegistration.setPort(Integer.parseInt(port)); //redisRegistration return redisRegistration; }).collect(Collectors.toList()); } @Override public List<String> getServices() { List<String> list = new ArrayList<>(); list.addAll(redisTemplate.keys("*")); return list; }}This class is mainly aimed at the service discovery of Redis Registration Center
5. Define automatic assembly classes to create corresponding beans
package com.hzgj.lyrk.member;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;@Configuration@EnableConfigurationProperties(RedisConfig.class)@ConditionalOnProperty(value = "spring.redis.registry.enabled", matchIfMissing = true)public class RedisRegistryAutoConfiguration { @Bean RedisServiceRegistry redisServiceRegistry(RedisConfig redisConfig) { System.out.println(redisConfig.getHost()); return new RedisServiceRegistry(); } @Bean RedisAutoServiceRegistration redisAutoServiceRegistration(RedisServiceRegistry redisServiceRegistry) { return new RedisAutoServiceRegistration(redisServiceRegistry, new AutoServiceRegistrationProperties()); } @Bean @Primary RedisDiscoveryClient redisDiscoveryClient() { return new RedisDiscoveryClient(); }}6. Define the startup class
package com.hzgj.lyrk.member;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration;import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;@EnableDiscoveryClient@SpringBootApplication(exclude = {SimpleDiscoveryClientAutoConfiguration.class, CompositeDiscoveryClientAutoConfiguration.class})public class MemberApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(MemberApplication.class, args); DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class); discoveryClient.getServices().forEach(action -> { System.out.println(action); }); }}Here, the default assembly of DiscoveryClient is excluded in the SpringbootApplication annotation.
When we successfully start, we can find that the console has output the corresponding service name and address:
We once again generate the jar file through gradle packaging and run:
java -jar member-server-0.0.1-SNAPSHOT.jar --server.port=8800
We can see that the service registered value that has been cached in redis:
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.