springcloudBus 2.x 事件追踪
Posted kevin-w
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springcloudBus 2.x 事件追踪相关的知识,希望对你有一定的参考价值。
最近由于工作需要,需要根据springcloudconfigserver搭建自己的配置管理服务,关于怎么搭建,怎么刷新等通过搜索网上资料很快完成,但是为了使我们的配置服务更完美,开始研究如果有多个conifig client实例的时候,其中一个实例进行配置刷新的时候,怎么保证或者追踪其他实例是否成功刷新,一开始网上搜索大致都说通过调用刷新端点(actuator/bus-refresh)后,调用端点(actuator/trace)就可以得到事件刷新纪录,大致得到的json响应长这样:
"timestamp": 1481098786017, "info": "signal": "spring.cloud.bus.ack", "event": "RefreshRemoteApplicationEvent", "id": "66d172e0-e770-4349-baf7-0210af62ea8d", "origin": "microservice-foo:8081", "destination": "**" , "timestamp": 1481098779073, "info": "signal": "spring.cloud.bus.sent", "type": "RefreshRemoteApplicationEvent", "id": "66d172e0-e770-4349-baf7-0210af62ea8d", "origin": "microservice-config-server:8080", "destination": "**:**"
上述json报文表明RefreshRemoteApplicationEvent已从 microservice-config-server:8080发送,广播到所有服务,并被microservice-foo:8081收到和确认。
但是当我启动我的configclient的时候查看控制台日志,并没有看到actuator暴露/actuator/trace接口。取而代之的是一个/actuator/httptrace接口,我尝试访问这个接口但是结果不是我想要的上述样子,几经查阅最终确认 actuator/trace是springbootactuator1.x版本才有的一个接口,不知什么原因在springboot2.x版本后官方取消了这个接口,以下代码段是springcloudbus 2.x和1.x的tracelistener源码
2.x
/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao ([email protected]) ***/ package org.springframework.cloud.bus.event; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.actuate.trace.http.HttpTraceRepository; import org.springframework.cloud.bus.event.AckRemoteApplicationEvent; import org.springframework.cloud.bus.event.SentApplicationEvent; import org.springframework.context.event.EventListener; public class TraceListener private static Log log = LogFactory.getLog(TraceListener.class); private HttpTraceRepository repository; public TraceListener(HttpTraceRepository repository) this.repository = repository; @EventListener public void onAck(AckRemoteApplicationEvent event) this.getReceivedTrace(event); @EventListener public void onSend(SentApplicationEvent event) this.getSentTrace(event); protected Map<String, Object> getSentTrace(SentApplicationEvent event) LinkedHashMap map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.sent"); map.put("type", event.getType().getSimpleName()); map.put("id", event.getId()); map.put("origin", event.getOriginService()); map.put("destination", event.getDestinationService()); if (log.isDebugEnabled()) log.debug(map); return map; protected Map<String, Object> getReceivedTrace(AckRemoteApplicationEvent event) LinkedHashMap map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.ack"); map.put("event", event.getEvent().getSimpleName()); map.put("id", event.getAckId()); map.put("origin", event.getOriginService()); map.put("destination", event.getAckDestinationService()); if (log.isDebugEnabled()) log.debug(map); return map;
1.x
package org.springframework.cloud.bus.event; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.context.event.EventListener; public class TraceListener private static Log log = LogFactory.getLog(TraceListener.class); private TraceRepository repository; public TraceListener(TraceRepository repository) this.repository = repository; @EventListener public void onAck(AckRemoteApplicationEvent event) this.repository.add(getReceivedTrace(event)); @EventListener public void onSend(SentApplicationEvent event) this.repository.add(getSentTrace(event)); protected Map<String, Object> getSentTrace(SentApplicationEvent event) Map map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.sent"); map.put("type", event.getType().getSimpleName()); map.put("id", event.getId()); map.put("origin", event.getOriginService()); map.put("destination", event.getDestinationService()); if (log.isDebugEnabled()) log.debug(map); return map; protected Map<String, Object> getReceivedTrace(AckRemoteApplicationEvent event) Map map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.ack"); map.put("event", event.getEvent().getSimpleName()); map.put("id", event.getAckId()); map.put("origin", event.getOriginService()); map.put("destination", event.getAckDestinationService()); if (log.isDebugEnabled()) log.debug(map); return map;
可以观察到的是其实两个版本都有生成我们想要的追踪记录,只是在2.x版本并没有把保存最终记录的map集合添加到repository中,关键是即使add,2.x的代码也不会成功,因为HttpTraceRepository并没有一个map引用的属性,不知道这是不是springcloud的一个bug。
其他探究过程不再赘述了,下面说下在springcloud2.x里面怎么实现事件追踪(参考springcloud1.x版本中源码)
1. 开启bus相关属性
spring:
application:
name: config-client1
cloud:
config:
label: master
profile: dev
uri: http://localhost:8888
bus:
enabled: true
trace:
enabled: true
ack:
enabled: true
2. 建立自己的TraceRepository和Trace
package com.kevin.config.client; import java.util.List; import java.util.Map; public interface CustomeTraceRepository List<CustomTrace> findAll(); void add(Map<String, Object> arg0);
package com.kevin.config.client; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Map; public class CustomTraceRepositoryImpl implements CustomeTraceRepository private int capacity = 100; private boolean reverse = true; private final List<CustomTrace> traces = new LinkedList(); public void setReverse(boolean reverse) List arg1 = this.traces; synchronized (this.traces) this.reverse = reverse; public void setCapacity(int capacity) List arg1 = this.traces; synchronized (this.traces) this.capacity = capacity; public List<CustomTrace> findAll() List arg0 = this.traces; System.out.println(this.traces.size()); synchronized (this.traces) return Collections.unmodifiableList(new ArrayList(this.traces)); public void add(Map<String, Object> map) CustomTrace trace = new CustomTrace(new Date(), map); List arg2 = this.traces; synchronized (this.traces) while (this.traces.size() >= this.capacity) this.traces.remove(this.reverse ? this.capacity - 1 : 0); if (this.reverse) this.traces.add(0, trace); else this.traces.add(trace);
package com.kevin.config.client; import java.util.Date; import java.util.Map; import org.springframework.util.Assert; public final class CustomTrace private final Date timestamp; private final Map<String, Object> info; public CustomTrace(Date timestamp, Map<String, Object> info) Assert.notNull(timestamp, "Timestamp must not be null"); Assert.notNull(info, "Info must not be null"); this.timestamp = timestamp; this.info = info; public Date getTimestamp() return this.timestamp; public Map<String, Object> getInfo() return this.info;
3. 建立自己的监听器,监听SentApplicationEvent和AckRemoteApplicationEvent
package com.kevin.config.client; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.cloud.bus.event.AckRemoteApplicationEvent; import org.springframework.cloud.bus.event.SentApplicationEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class TraceListener private static Log log = LogFactory.getLog(TraceListener.class); private CustomeTraceRepository repository; public TraceListener(CustomeTraceRepository repository) this.repository = repository; @EventListener public void onAck(AckRemoteApplicationEvent event) this.getReceivedTrace(event); @EventListener public void onSend(SentApplicationEvent event) this.getSentTrace(event); protected Map<String, Object> getSentTrace(SentApplicationEvent event) LinkedHashMap map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.sent"); map.put("type", event.getType().getSimpleName()); map.put("id", event.getId()); map.put("origin", event.getOriginService()); map.put("destination", event.getDestinationService()); if (log.isDebugEnabled()) log.debug(map); this.repository.add(map); return map; protected Map<String, Object> getReceivedTrace(AckRemoteApplicationEvent event) LinkedHashMap map = new LinkedHashMap(); map.put("signal", "spring.cloud.bus.ack"); map.put("event", event.getEvent().getSimpleName()); map.put("id", event.getAckId()); map.put("origin", event.getOriginService()); map.put("destination", event.getAckDestinationService()); if (log.isDebugEnabled()) log.debug(map); this.repository.add(map); return map;
4. 让spring管理建立的repository
@Bean public CustomTraceRepositoryImpl customeTraceRepository() return new CustomTraceRepositoryImpl();
5 .最后暴露一个接口从repository获取数据
@RequestMapping(value = "/trace") public List<CustomTrace> trace(HttpServletRequest request) throws IOException return customeTraceRepository().findAll();
至此,就可以通过这个接口获取事件追踪记录,本例子中repository默认存储100条,如果超出就会覆盖首尾的记录,如果有其他特殊需求可以自行实现。
注意:在建立自己的repository和trace的时候类的名字最好不要和spring里面的一样,否则会报一些莫名的错误,具体原因没有细究,反正我是改了名字就可以。
以上是关于springcloudBus 2.x 事件追踪的主要内容,如果未能解决你的问题,请参考以下文章