深入理解SpringCloud之DiscoveryClient探究

小编 2026-06-04 阅读:1962 评论:0
  当我们使用@DiscoveryClient注解的时候,会不会有如下疑问:它为什么会进行注册服...

  当我们使用@DiscoveryClient注解的时候,会不会有如下疑问:它为什么会进行注册服务的操作,它不是应该用作服务发现的吗?下面我们就来深入的探究一下其源码。

一、Springframework的LifeCycle接口

  要搞明白这个问题我们需要了解一下这个重要的接口:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
/* * 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, e.g. 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();}
View Code

  该接口定义启动/停止生命周期控制方法,当spring ioc容器启动或停止时将发送一个启动或者停止的信号通知到各个组件,因此我们可以在对应的方法里做我们想要的事情。我们可以通过类图发现我们常用的ClasspathXmlApplicationContext类就实现了该接口

深入理解SpringCloud之DiscoveryClient探究

   下面我们来简单演示一下案例,创建类MyLifeCycle:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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;    }}
View Code

  在这里我们继承SmartLifeCycle该接口继承了LifeCycle, isRunning方法用于检测当前的组件是否处在运行状态,注意只有当isRunning返回值为false才可以运行

  我们把MyLifeCycle配置到spring配置文件里,通过ClassPathXmlApplicationContext运行 会得到如下结果:

深入理解SpringCloud之DiscoveryClient探究

  另外在这里的getPhase方法,这个是定义阶段值(可以理解为优先级,值越小对应的LifeCycle越先执行)

  

二、DiscoveryClient源码探究

@EnableDiscoveyClient

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
/* * 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.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;}
View Code

  请注意 @Import(EnableDiscoveryClientImportSelector.class) 我们可以参考一下这个类:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
/* * 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;    }}
View Code

  这个类重写的方法来自于接口 ImportSelector,我们可以根据 if(autoRegister)下的代码追踪到类:org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration,我们来看一下结构图:

深入理解SpringCloud之DiscoveryClient探究

我们可以得知这个类实现了Lifecycle接口,那么我们看一看start方法,此方法在它的父类AbstractDiscoveryLifecycle里:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
/* * 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();        }    }}
View Code

注意在start方法里有一段这个代码:

if (!this.running.get() && getConfiguredPort() > 0) {            register();            if (shouldRegisterManagement()) {                registerManagement();            }            this.context.publishEvent(new InstanceRegisteredEvent<>(this,                    getConfiguration()));            this.running.compareAndSet(false, true);        }

请注意register() 这个方法是本类里的抽象方法。那么我们回过头看一下AbstractAutoServiceRegistration类里的代码,我这里只贴出关键部分:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
//.....    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());    }
View Code

我们可以发现在构造函数里传了一个ServiceRegistry类型,这个接口是SpringCloud给我们提供用于服务注册的接口。在这里EurekaServiceRegistry就是实现了此接口:

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
/* * 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 possibly 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 disposed            //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() {    }}
View Code

那么至此我们可以总结如下几点:

  1、使用@DiscoveryClient注册服务是利用了LifeCycle机制,在容器启动时会执行ServiceRegistry的register()方法。

  2、使用@DiscoveryClient要比@EnableEurekaClient与@EnableEurekaServer更灵活,因为它屏蔽了对服务注册的实现,我们甚至可以自定义注册中心。

  3、它还会自动去寻找DiscoveryClient接口的实现用作服务发现

 

三、Discoveryclient实战之redis注册中心

 下面我们实现一个基于redis为注册中心的需求,来理解一下Discoveryclient。顺便理解一下Springcloud重要的接口:ServiceRegistry,ServiceInstance,再此之前我们先添加对redis的支持:

   compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis'

1、实现Registration接口

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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;            // 遍历所有的网络接口            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();                // 在所有的接口下再遍历IP                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();                    if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址                        if (inetAddr.isSiteLocalAddress()) {                            // 如果是site-local地址,就是它了                            return inetAddr;                        } else if (candidateAddress == null) {                            // site-local类型的地址未被发现,先记录候选地址                            candidateAddress = inetAddr;                        }                    }                }            }            if (candidateAddress != null) {                return candidateAddress;            }            // 如果没有发现 non-loopback地址.只能用最次选的方案            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();            return jdkSuppliedAddress;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }}
View Code

  该接口继承了ServiceIntance,那么此接口最主要作用就是定义了一个服务实例的规范,比如说它的serviceId是什么,端口号是什么等

2、实现ServiceRegistry的接口

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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;    }}
View Code

  该接口主要作用是定义如何进行服务注册 ,服务注销,设置与获取服务状态等操作

3、继承 AbstractAutoServiceRegistration抽象类

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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.AutoServiceRegistrationProperties;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;    }}
View Code

 

4、定义DiscoveryClient的实现类RedisDiscoveryClient

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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 "redis注册中心的服务发现";    }    @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;    }}
View Code

  该类主要是针对于redis注册中心的服务发现

5、定义自动装配的类用以创建对应的bean

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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();    }}
View Code

6、定义启动类

深入理解SpringCloud之DiscoveryClient探究深入理解SpringCloud之DiscoveryClient探究
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);        });    }}
View Code

  这里在SpringbootApplication注解里排除DiscoveryClient的默认装配。

当我们启动成功后可以发现,控制台已经输出对应的服务名称与地址:

深入理解SpringCloud之DiscoveryClient探究

  我们再次通过gradle打包生成jar文件并运行:

java -jar member-server-0.0.1-SNAPSHOT.jar --server.port=8800

  我们可以看到redis里已经缓存的有服务注册的值了:

深入理解SpringCloud之DiscoveryClient探究

 

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表