91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Cloud學習教程之DiscoveryClient的深入探究

發布時間:2020-08-21 14:27:40 來源:腳本之家 閱讀:389 作者:洛陽融科聶晨 欄目:編程語言

前言

當我們使用@DiscoveryClient注解的時候,會不會有如下疑問:它為什么會進行注冊服務的操作,它不是應該用作服務發現的嗎?下面我們就來深入的探究一下其源碼。

一、Springframework的LifeCycle接口

要搞明白這個問題我們需要了解一下這個重要的接口:

/*
 * 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();
}

該接口定義啟動/停止生命周期控制方法,當spring ioc容器啟動或停止時將發送一個啟動或者停止的信號通知到各個組件,因此我們可以在對應的方法里做我們想要的事情。我們可以通過類圖發現我們常用的ClasspathXmlApplicationContext類就實現了該接口

Spring Cloud學習教程之DiscoveryClient的深入探究

下面我們來簡單演示一下案例,創建類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;
 }
}

在這里我們繼承SmartLifeCycle該接口繼承了LifeCycle, isRunning方法用于檢測當前的組件是否處在運行狀態,注意只有當isRunning返回值為false才可以運行

我們把MyLifeCycle配置到spring配置文件里,通過ClassPathXmlApplicationContext運行 會得到如下結果:

Spring Cloud學習教程之DiscoveryClient的深入探究

另外在這里的getPhase方法,這個是定義階段值(可以理解為優先級,值越小對應的LifeCycle越先執行)

二、DiscoveryClient源碼探究

@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 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;
}

請注意 @Import(EnableDiscoveryClientImportSelector.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;
 }
}

這個類重寫的方法來自于接口 ImportSelector,我們可以根據 if(autoRegister)下的代碼追蹤到類:org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration ,我們來看一下結構圖:

Spring Cloud學習教程之DiscoveryClient的深入探究

我們可以得知這個類實現了Lifecycle接口,那么我們看一看start方法,此方法在它的父類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
 */
@Deprecated
public 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();
 }
 }
}

注意在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類里的代碼,我這里只貼出關鍵部分:

//.....

 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());
 }

我們可以發現在構造函數里傳了一個ServiceRegistry類型,這個接口是SpringCloud給我們提供用于服務注冊的接口。在這里EurekaServiceRegistry就是實現了此接口:

/*
 * 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() {
 }
}

那么至此我們可以總結如下幾點:

  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接口

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;

@Component
public 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;
 }
}

該接口繼承了ServiceIntance,那么此接口最主要作用就是定義了一個服務實例的規范,比如說它的serviceId是什么,端口號是什么等

2、實現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;
 }
}

該接口主要作用是定義如何進行服務注冊 ,服務注銷,設置與獲取服務狀態等操作

3、繼承 AbstractAutoServiceRegistration抽象類

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;
 }
}

4、定義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 "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;
 }
}

該類主要是針對于redis注冊中心的服務發現

5、定義自動裝配的類用以創建對應的bean

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、定義啟動類

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);
 });
 }
}

這里在SpringbootApplication注解里排除DiscoveryClient的默認裝配。

當我們啟動成功后可以發現,控制臺已經輸出對應的服務名稱與地址:

Spring Cloud學習教程之DiscoveryClient的深入探究

我們再次通過gradle打包生成jar文件并運行:

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

我們可以看到redis里已經緩存的有服務注冊的值了:

Spring Cloud學習教程之DiscoveryClient的深入探究

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

韶关市| 南江县| 固始县| 盐津县| 南昌市| 兴化市| 沧州市| 宜川县| 凌云县| 陈巴尔虎旗| 瓮安县| 绥芬河市| 绥阳县| 许昌市| 吉木萨尔县| 鹤庆县| 佛学| 城口县| 砚山县| 玛多县| 勐海县| 新闻| 五台县| 和龙市| 华容县| 平度市| 马鞍山市| 安阳县| 冷水江市| 广饶县| 太仆寺旗| 凤冈县| 建瓯市| 贡山| 宁波市| 兴海县| 柳河县| 儋州市| 色达县| 盐源县| 北京市|