赞
踩
在一些场景下,我们需要监听eureka服务中心的一些状态,譬如某个微服务挂掉了,我们希望能监听到,并给管理员发送邮件通知。
Eureka的server端会发出5个事件通知,分别是:
EurekaInstanceCanceledEvent 服务下线事件
EurekaInstanceRegisteredEvent 服务注册事件
EurekaInstanceRenewedEvent 服务续约事件
EurekaRegistryAvailableEvent Eureka注册中心启动事件
EurekaServerStartedEvent Eureka Server启动事件
我们可以从源码中很方便地看到
eureka的server端源码一共也没几个类,Controller是给界面用的,还有一些配置类,我们简单来看几个。
- @Configuration
- @CommonsLog
- public class EurekaServerInitializerConfiguration
- implements ServletContextAware, SmartLifecycle, Ordered {
-
- ...
-
- @Override
- public void start() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- //TODO: is this class even needed now?
- // 初始化eureka server
- eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
- log.info("Started Eureka Server");
-
- // 传递eureka注册事件,找来找去没看到有listen去处理这件事件
- // spring包中没有去处理,如果我们有需要可以自己处理
- // https://github.com/spring-cloud/spring-cloud-netflix/issues/1726
- publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
- // 设置在spring容器关闭的时候执行stop方法
- EurekaServerInitializerConfiguration.this.running = true;
- publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
- }
- catch (Exception ex) {
- // Help!
- log.error("Could not initialize Eureka servlet context", ex);
- }
- }
- }).start();
- }
-
-
- @Bean
- public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
- EurekaServerContext serverContext) {
- return new EurekaServerBootstrap(this.applicationInfoManager,
- this.eurekaClientConfig, this.eurekaServerConfig, registry,
- serverContext);
- }
- ...
- }

- @CommonsLog
- public class EurekaServerBootstrap {
-
- ....
-
- public void contextInitialized(ServletContext context) {
- try {
- //初始化eureka环境
- initEurekaEnvironment();
- //初始化eureka上下文
- initEurekaServerContext();
-
- context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
- }
- catch (Throwable e) {
- log.error("Cannot bootstrap eureka server :", e);
- throw new RuntimeException("Cannot bootstrap eureka server :", e);
- }
- }
-
- protected void initEurekaEnvironment() throws Exception {
- log.info("Setting the eureka configuration..");
-
- //如果在云环境中运行,需要传递java命令行属性-Deureka.datacenter = cloud,以便Eureka客户端/服务器知道初始化AWS云特定的信息
- String dataCenter = ConfigurationManager.getConfigInstance()
- .getString(EUREKA_DATACENTER);
- if (dataCenter == null) {
- log.info(
- "Eureka data center value eureka.datacenter is not set, defaulting to default");
- ConfigurationManager.getConfigInstance()
- .setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
- }
- else {
- ConfigurationManager.getConfigInstance()
- .setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
- }
-
- //eureka 运行环境,java命令行属性-Deureka.environment=eureka-client-{test,prod}
- String environment = ConfigurationManager.getConfigInstance()
- .getString(EUREKA_ENVIRONMENT);
- if (environment == null) {
- ConfigurationManager.getConfigInstance()
- .setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
- log.info(
- "Eureka environment value eureka.environment is not set, defaulting to test");
- }
- else {
- ConfigurationManager.getConfigInstance()
- .setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, environment);
- }
- }
-
- // eureka使用XStream来对json、xml格式的转换
- protected void initEurekaServerContext() throws Exception {
- // 向后兼容
- //注册状态转换器
- JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
- XStream.PRIORITY_VERY_HIGH);
- XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(),
- XStream.PRIORITY_VERY_HIGH);
-
- //判断是否亚马逊的数据中心
- if (isAws(this.applicationInfoManager.getInfo())) {
- this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
- this.eurekaClientConfig, this.registry, this.applicationInfoManager);
- //
- this.awsBinder.start();
- }
-
- //初始化eureka server上下文
- EurekaServerContextHolder.initialize(this.serverContext);
-
- log.info("Initialized server context");
-
- // 从相邻的eureka节点复制注册表
- int registryCount = this.registry.syncUp();
- // 默认每30秒发送心跳,1分钟就是2次
- // 修改eureka状态为up
- this.registry.openForTraffic(this.applicationInfoManager, registryCount);
-
- // 注册所有监控
- EurekaMonitors.registerAllStats();
- }
-
- ...
- }

- public class InstanceRegistry extends PeerAwareInstanceRegistryImpl implements ApplicationContextAware {
- private static final Log log = LogFactory.getLog(InstanceRegistry.class);
- private ApplicationContext ctxt;
- private int defaultOpenForTrafficCount;
-
- public InstanceRegistry(EurekaServerConfig serverConfig, EurekaClientConfig clientConfig, ServerCodecs serverCodecs, EurekaClient eurekaClient, int expectedNumberOfRenewsPerMin, int defaultOpenForTrafficCount) {
- super(serverConfig, clientConfig, serverCodecs, eurekaClient);
- this.expectedNumberOfRenewsPerMin = expectedNumberOfRenewsPerMin;
- this.defaultOpenForTrafficCount = defaultOpenForTrafficCount;
- }
-
- public void setApplicationContext(ApplicationContext context) throws BeansException {
- this.ctxt = context;
- }
-
- public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
- super.openForTraffic(applicationInfoManager, count == 0 ? this.defaultOpenForTrafficCount : count);
- }
-
- public void register(InstanceInfo info, int leaseDuration, boolean isReplication) {
- this.handleRegistration(info, leaseDuration, isReplication);
- super.register(info, leaseDuration, isReplication);
- }
-
- public void register(InstanceInfo info, boolean isReplication) {
- this.handleRegistration(info, this.resolveInstanceLeaseDuration(info), isReplication);
- super.register(info, isReplication);
- }
-
- public boolean cancel(String appName, String serverId, boolean isReplication) {
- this.handleCancelation(appName, serverId, isReplication);
- return super.cancel(appName, serverId, isReplication);
- }
-
- public boolean renew(String appName, String serverId, boolean isReplication) {
- this.log("renew " + appName + " serverId " + serverId + ", isReplication {}" + isReplication);
- List<Application> applications = this.getSortedApplications();
- Iterator var5 = applications.iterator();
-
- while(var5.hasNext()) {
- Application input = (Application)var5.next();
- if (input.getName().equals(appName)) {
- InstanceInfo instance = null;
- Iterator var8 = input.getInstances().iterator();
-
- while(var8.hasNext()) {
- InstanceInfo info = (InstanceInfo)var8.next();
- if (info.getId().equals(serverId)) {
- instance = info;
- break;
- }
- }
- //这里发布重连事件
- this.publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instance, isReplication));
- break;
- }
- }
-
- return super.renew(appName, serverId, isReplication);
- }
-
- protected boolean internalCancel(String appName, String id, boolean isReplication) {
- this.handleCancelation(appName, id, isReplication);
- return super.internalCancel(appName, id, isReplication);
- }
-
- private void handleCancelation(String appName, String id, boolean isReplication) {
- this.log("cancel " + appName + ", serverId " + id + ", isReplication " + isReplication);
- this.publishEvent(new EurekaInstanceCanceledEvent(this, appName, id, isReplication));
- }
-
- private void handleRegistration(InstanceInfo info, int leaseDuration, boolean isReplication) {
- this.log("register " + info.getAppName() + ", vip " + info.getVIPAddress() + ", leaseDuration " + leaseDuration + ", isReplication " + isReplication);
- this.publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration, isReplication));
- }
-
- private void log(String message) {
- if (log.isDebugEnabled()) {
- log.debug(message);
- }
-
- }
-
- private void publishEvent(ApplicationEvent applicationEvent) {
- this.ctxt.publishEvent(applicationEvent);
- }
-
- private int resolveInstanceLeaseDuration(InstanceInfo info) {
- int leaseDuration = 90;
- if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
- leaseDuration = info.getLeaseInfo().getDurationInSecs();
- }
-
- return leaseDuration;
- }
- }

差不多能用上的就这几个类了,这5个server端事件在这几个类中都能找到。
知道了事件名,要监听就很简单了
- package com.tianyalei.server;
-
- import com.netflix.appinfo.InstanceInfo;
- import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
- import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
- import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRenewedEvent;
- import org.springframework.cloud.netflix.eureka.server.event.EurekaRegistryAvailableEvent;
- import org.springframework.cloud.netflix.eureka.server.event.EurekaServerStartedEvent;
- import org.springframework.context.event.EventListener;
- import org.springframework.stereotype.Component;
-
- /**
- * Created by wuweifeng on 2017/10/10.
- */
- @Component
- public class EurekaStateChangeListener {
-
- @EventListener
- public void listen(EurekaInstanceCanceledEvent eurekaInstanceCanceledEvent) {
- //服务断线事件
- String appName = eurekaInstanceCanceledEvent.getAppName();
- String serverId = eurekaInstanceCanceledEvent.getServerId();
- System.out.println(appName);
- System.out.println(serverId);
- }
-
- @EventListener
- public void listen(EurekaInstanceRegisteredEvent event) {
- InstanceInfo instanceInfo = event.getInstanceInfo();
- System.out.println(instanceInfo);
- }
-
- @EventListener
- public void listen(EurekaInstanceRenewedEvent event) {
- event.getAppName();
- event.getServerId();
- }
-
- @EventListener
- public void listen(EurekaRegistryAvailableEvent event) {
-
- }
-
- @EventListener
- public void listen(EurekaServerStartedEvent event) {
- //Server启动
- }
- }

在server项目里加上这个监听类,然后在各个事件被触发时就能在这里监听并处理了。
譬如我启动一个client
在这里就能看到新注册的client的各项详细信息。
然后我再关掉client
可以看到挂掉的client的appName,serverId等信息。那么我们就可以在这里做一些处理,譬如邮件通知管理员,某某服务挂掉了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。