一.前言
近期由于公司不同平台项目之间的业务整合,需要做到相互访问! 每个平台均有自己的注册中心和服务,且注册中心相互之间并没有相互注册!
借助spring的事件监听,在eureka-server端监听服务注册,将所有服务的ip和port存放至redis库,然后让其他平台服务通过redis库获取ip和端口号,进而进行http调用.结构图如下:
二.事件解析
事件列表
在org.springframework.cloud.netflix.eureka.server.event
包下会发现如下类:
EurekaInstanceCanceledEvent
: 服务下线事件EurekaInstanceRegisteredEvent
: 服务注册事件EurekaInstanceRenewedEvent
: 服务续约事件EurekaRegistryAvailableEvent
: eureka注册中心启动事件EurekaServerStartedEvent
: eureka server启动时间
源码分析
打开org.springframework.cloud.netflix.eureka.server.InstanceRegistry
类,会发现当eureka服务续约、注册、取消等时,spring会publish不同的事件,对应的事件类就是上面的列表.
续约事件
@Override public boolean renew(final String appName, final String serverId, boolean isReplication) { log("renew " + appName + " serverId " + serverId + ", isReplication {}" + isReplication); Listapplications = getSortedApplications(); for (Application input : applications) { if (input.getName().equals(appName)) { InstanceInfo instance = null; for (InstanceInfo info : input.getInstances()) { if (info.getId().equals(serverId)) { instance = info; break; } } // 发布续约事件 publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instance, isReplication)); break; } } return super.renew(appName, serverId, isReplication); }
注册事件
@Override public void register(InstanceInfo info, int leaseDuration, boolean isReplication) { handleRegistration(info, leaseDuration, isReplication); super.register(info, leaseDuration, isReplication); } private void handleRegistration(InstanceInfo info, int leaseDuration, boolean isReplication) { log("register " + info.getAppName() + ", vip " + info.getVIPAddress() + ", leaseDuration " + leaseDuration + ", isReplication " + isReplication); // 发布注册事件 publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration, isReplication)); }
事件监听
通过上面的源码追溯,我们已经得到对应的事件类了,所以现在要做的仅仅是监听对应的事件即可,至此已经完成了我们所需要对事件监听后的业务处理!
@Component public class EurekaStateChangeListener { @Value("${iptable.platform}") private String platform; @Autowired private RedisTemplateredisTemplate; private static Logger logger = LoggerFactory.getLogger(EurekaStateChangeListener.class); private static final String COLON = ":"; @EventListener//(condition = "#event.replication==false") public void listen(EurekaInstanceCanceledEvent eurekaInstanceCanceledEvent) { // 服务断线事件 String appName = eurekaInstanceCanceledEvent.getAppName(); String serverId = eurekaInstanceCanceledEvent.getServerId(); Objects.requireNonNull(appName, "服务名不能为空!"); SetOperations opsForSet = redisTemplate.opsForSet(); opsForSet.remove((platform + appName).toLowerCase(), serverId); logger.info(">>>>>>> 失效服务:{},已被剔除!", serverId); } @EventListener//(condition = "#event.replication==false") public void listen(EurekaInstanceRegisteredEvent event) { // 服务注册 InstanceInfo instanceInfo = event.getInstanceInfo(); String appName = instanceInfo.getAppName(); Objects.requireNonNull(appName, "服务名不能为空!"); SetOperations opsForSet = redisTemplate.opsForSet(); opsForSet.add((platform + appName).toLowerCase(), instanceInfo.getIPAddr() + COLON + instanceInfo.getPort()); logger.info(">>>>>>> 服务名:{},端口号:{},已缓存至redis", appName, instanceInfo.getPort()); } @EventListener//(condition = "#event.replication==false") public void listen(EurekaInstanceRenewedEvent event) { // 服务续约 logger.info(">>>>>>>>>>>>>>>Server续约:" + event.getServerId()); } @EventListener public void listen(EurekaRegistryAvailableEvent event) { // 注册中心启动 logger.info(">>>>>>>>>>>>>>>Server注册中心:" + event); } @EventListener public void listen(EurekaServerStartedEvent event) { // Server启动 logger.info(">>>>>>>>>>>>>>>Server启动:" + event); } }
注意事项
[ ] 版本问题:
当时项目组用的SpringCloud版本是Brixton.RELEASE,该版本有一个问题就是服务注册和下线并不会出发对应的事件,所以导致一直监听不到.解决的办法也很简单,只要升级版本即可,我已经升级到最新版本Finchley.RELEASE.
传送门,点我
[ ] 重复监听:
例如,在续约的时候,eureka会发出2条EurekaInstanceRenewedEvent
事件,但是2条事件的属性却不一样!一个事件的属性replication为true,另外一个为false.如果我们只想处理replication=true的事件,如下配置即可:
@EventListener(condition = "#event.replication==false") public void listen(EurekaInstanceRenewedEvent event) { // 服务续约 logger.info(">>>>>>>>>>>>>>>Server续约:" + event.getServerId()); }
GitHub代码,点我
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。