您好,登錄后才能下訂單哦!
前言
當我們使用@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類就實現了該接口
下面我們來簡單演示一下案例,創建類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運行 會得到如下結果:
另外在這里的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
,我們來看一下結構圖:
我們可以得知這個類實現了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的默認裝配。
當我們啟動成功后可以發現,控制臺已經輸出對應的服務名稱與地址:
我們再次通過gradle打包生成jar文件并運行:
java -jar member-server-0.0.1-SNAPSHOT.jar --server.port=8800
我們可以看到redis里已經緩存的有服務注冊的值了:
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。