欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Cloud學(xué)習(xí)教程之DiscoveryClient的深入探究

 更新時(shí)間:2018年04月23日 10:52:23   作者:洛陽融科聶晨  
這篇文章主要給大家介紹了關(guān)于Spring Cloud學(xué)習(xí)教程之DiscoveryClient的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。

前言

當(dāng)我們使用@DiscoveryClient注解的時(shí)候,會(huì)不會(huì)有如下疑問:它為什么會(huì)進(jìn)行注冊(cè)服務(wù)的操作,它不是應(yīng)該用作服務(wù)發(fā)現(xiàn)的嗎?下面我們就來深入的探究一下其源碼。

一、Springframework的LifeCycle接口

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

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

該接口定義啟動(dòng)/停止生命周期控制方法,當(dāng)spring ioc容器啟動(dòng)或停止時(shí)將發(fā)送一個(gè)啟動(dòng)或者停止的信號(hào)通知到各個(gè)組件,因此我們可以在對(duì)應(yīng)的方法里做我們想要的事情。我們可以通過類圖發(fā)現(xiàn)我們常用的ClasspathXmlApplicationContext類就實(shí)現(xiàn)了該接口

下面我們來簡(jiǎn)單演示一下案例,創(chuàng)建類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方法用于檢測(cè)當(dāng)前的組件是否處在運(yùn)行狀態(tài),注意只有當(dāng)isRunning返回值為false才可以運(yùn)行

我們把MyLifeCycle配置到spring配置文件里,通過ClassPathXmlApplicationContext運(yùn)行 會(huì)得到如下結(jié)果:

另外在這里的getPhase方法,這個(gè)是定義階段值(可以理解為優(yōu)先級(jí),值越小對(duì)應(yīng)的LifeCycle越先執(zhí)行)

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

請(qǐng)注意 @Import(EnableDiscoveryClientImportSelector.class) 我們可以參考一下這個(gè)類:

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

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

我們可以得知這個(gè)類實(shí)現(xiàn)了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方法里有一段這個(gè)代碼:

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

請(qǐng)注意register() 這個(gè)方法是本類里的抽象方法。那么我們回過頭看一下AbstractAutoServiceRegistration類里的代碼,我這里只貼出關(guān)鍵部分:

//.....

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

我們可以發(fā)現(xiàn)在構(gòu)造函數(shù)里傳了一個(gè)ServiceRegistry類型,這個(gè)接口是SpringCloud給我們提供用于服務(wù)注冊(cè)的接口。在這里EurekaServiceRegistry就是實(shí)現(xiàn)了此接口:

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

那么至此我們可以總結(jié)如下幾點(diǎn):

  1、使用@DiscoveryClient注冊(cè)服務(wù)是利用了LifeCycle機(jī)制,在容器啟動(dòng)時(shí)會(huì)執(zhí)行ServiceRegistry的register()方法。

  2、使用@DiscoveryClient要比@EnableEurekaClient與@EnableEurekaServer更靈活,因?yàn)樗帘瘟藢?duì)服務(wù)注冊(cè)的實(shí)現(xiàn),我們甚至可以自定義注冊(cè)中心。

  3、這里面還會(huì)自動(dòng)去尋找DiscoveryClient接口的實(shí)現(xiàn)用作服務(wù)發(fā)現(xiàn)

三、Discoveryclient實(shí)戰(zhàn)之redis注冊(cè)中心

 下面我們實(shí)現(xiàn)一個(gè)基于redis為注冊(cè)中心的需求,來理解一下Discoveryclient。順便理解一下Springcloud重要的接口:ServiceRegistry,ServiceInstance,再此之前我們先添加對(duì)redis的支持:

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

1、實(shí)現(xiàn)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;
  // 遍歷所有的網(wǎng)絡(luò)接口
  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類型的地址未被發(fā)現(xiàn),先記錄候選地址
    candidateAddress = inetAddr;
   }
   }
  }
  }
  if (candidateAddress != null) {
  return candidateAddress;
  }
  // 如果沒有發(fā)現(xiàn) non-loopback地址.只能用最次選的方案
  InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
  return jdkSuppliedAddress;
 } catch (Exception e) {
  e.printStackTrace();
 }
 return null;
 }
}

該接口繼承了ServiceIntance,那么此接口最主要作用就是定義了一個(gè)服務(wù)實(shí)例的規(guī)范,比如說它的serviceId是什么,端口號(hào)是什么等

2、實(shí)現(xiàn)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;
 }
}

該接口主要作用是定義如何進(jìn)行服務(wù)注冊(cè) ,服務(wù)注銷,設(shè)置與獲取服務(wù)狀態(tài)等操作

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的實(shí)現(xiàn)類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注冊(cè)中心的服務(wù)發(fā)現(xiàn)";
 }

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

該類主要是針對(duì)于redis注冊(cè)中心的服務(wù)發(fā)現(xiàn)

5、定義自動(dòng)裝配的類用以創(chuàng)建對(duì)應(yīng)的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、定義啟動(dòng)類

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的默認(rèn)裝配。

當(dāng)我們啟動(dòng)成功后可以發(fā)現(xiàn),控制臺(tái)已經(jīng)輸出對(duì)應(yīng)的服務(wù)名稱與地址:

我們?cè)俅瓮ㄟ^gradle打包生成jar文件并運(yùn)行:

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

我們可以看到redis里已經(jīng)緩存的有服務(wù)注冊(cè)的值了:

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • java 內(nèi)部類的詳解及實(shí)例

    java 內(nèi)部類的詳解及實(shí)例

    這篇文章主要介紹了 java 內(nèi)部類的詳解及實(shí)例的相關(guān)資料,這里提供了兩種內(nèi)部類的實(shí)現(xiàn)方法,并給出實(shí)例,需要的朋友可以參考下
    2017-08-08
  • IntelliJ IDEA中出現(xiàn)

    IntelliJ IDEA中出現(xiàn)"PSI and index do not match"錯(cuò)誤的解決辦法

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA中出現(xiàn)"PSI and index do not match"錯(cuò)誤的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • java 一個(gè)截取字符串的函數(shù)

    java 一個(gè)截取字符串的函數(shù)

    java 編寫一個(gè)截取字符串的函數(shù),輸入為一個(gè)字符串和字節(jié)數(shù),輸出為按字節(jié)截取的字符串。 要求不能出現(xiàn)截半的情況
    2017-02-02
  • FluentMybatis實(shí)現(xiàn)mybatis動(dòng)態(tài)sql拼裝和fluent api語法

    FluentMybatis實(shí)現(xiàn)mybatis動(dòng)態(tài)sql拼裝和fluent api語法

    本文主要介紹了FluentMybatis實(shí)現(xiàn)mybatis動(dòng)態(tài)sql拼裝和fluent api語法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 最新評(píng)論