传送唯一request id在项目或者Micro services之间

  • 背景介绍
  • Log4j format 中加requestid
  • Rest API 调用
  • JMS message 传输之间
  • 线程池中的线程
  • Hessian call 之间

背景介绍

随着项目中要把原来的几个项目变成许多 MircoServices. 所谓的 Micro services化把一个大的项目。
带来一些其它的问题。比如怎么样更方便的查看log,因为项目都变成了一个一个小的项目了。
每个项目的log 文件都在它们怎么自己的项目里。尽管我们用了ELK把所有的log 到发到Elastic search 通过 logstash. 但是没有办法把项目之间的log message 串联在一起显示。只能通过时间的比对或者是其它的信息。

由于这个原因。我引入一个request id 在项目直接调用。这样我们就可以直接用request id 搜索相关的log message 了。再也不用因为很难找到被调用项目的log而发愁了。

Log4j format 中加requestid

log4j.appender.file.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss,SSS}][%X{REQUEST_ID}] %-5p[%t](%C:%L) - %m%n

Rest API 调用

由于我用MDC 还保存我的requestId 的。所有 调用之前要取一下requestId 再MDC里
发送端要加下面的 interceptor

public class RestfulServiceLogInterceptor implements ClientHttpRequestInterceptor{@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {String requestId= (String) MDC.get("REQUEST_ID");if(StringUtils.isEmpty(requestId)) {requestId=UUID.randomUUID().toString();}request.getHeaders().add("REQUEST_ID", requestId);return execution.execute(request, body);}
}
public class RestfulServiceAsyncLogInterceptor implements AsyncClientHttpRequestInterceptor{@Overridepublic ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body, AsyncClientHttpRequestExecution execution) throws IOException{String requestId= (String) MDC.get("REQUEST_ID");if(StringUtils.isEmpty(requestId)) {requestId=UUID.randomUUID().toString();}request.getHeaders().add("REQUEST_ID", requestId);return execution.execute(request, body);}}

被调用端要加下面的Filter。


@Component
public class LogFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {try {if (servletRequest != null && servletRequest instanceof HttpServletRequest) {HttpServletRequest req = (HttpServletRequest) servletRequest;String requestId = req.getHeader("REQUEST_ID");MDC.put("REQUEST_ID", requestId );}filterChain.doFilter(servletRequest, servletResponse);} finally {LogUtils.clearHeaderPropertiesInMDC();}}}

JMS message 传输之间

发送JMS 端, 发送的时候要用下面的类包装message.


public abstract class BaseMessageCreator implements MessageCreator{@Overridepublic Message createMessage(Session session) throws JMSException {Message message = this.createInternalMessage(session);this.postProcess(message);return message;}public void postProcess(Message message){String requestId= (String) MDC.get("REQUEST_ID");if(StringUtils.isEmpty(requestId)) {requestId=UUID.randomUUID().toString();}message.setStringProperty("REQUEST_ID", requestId);}protected abstract Message createInternalMessage(Session session) throws JMSException;}

JMS 接受端 , 要用下面类取message header 的requestid.
我用的是AOP. 当然如果你觉得麻烦。也可以直接再你的JMS listner上, 直接取。


@Aspect
public class JmsTransactionAspectLogger {@Pointcut("execution(public * javax.jms.MessageListener.onMessage(..))")private void isMessageListener() {}@Pointcut("execution(public * org.springframework.jms.listener.SessionAwareMessageListener.onMessage(..))")private void isSessionAwareMessageListener() {}@Pointcut("isMessageListener() || isSessionAwareMessageListener()")private void jmsTransactionMethod() {}public void beforeJmsListener(JoinPoint joinPoint) {try {Object[] args = joinPoint.getArgs();for (int i = 0; i < args.length; i++) {Object arg = args[i];if (arg instanceof Message) {Message message = (Message) arg;String requestId = message.getStringProperty("REQUEST_ID");MDC.put("REQUEST_ID", requestId );}}} catch (Exception ex) {throw e;}}@Around(value = "jmsTransactionMethod()")public Object handleJmsTransaction(final ProceedingJoinPoint joinPoint) throws Throwable {this.beforeJmsListener(joinPoint);try {retValue = joinPoint.proceed(joinPoint.getArgs());} catch (Throwable ex) {throw ex;} finally {this.afterJmsListener(joinPoint, startTime);}return retValue;}public void afterJmsListener(JoinPoint joinPoint, long startTime) {LogUtils.clearHeaderPropertiesInMDC();}

线程池中的线程

线程要用继承下面的抽象类。

如果不是用的线程中的线程,那么没问题
因为 MDC中的值可以从主线程中传过去的。

public class MdcContextHolder {private String requestId;public MdcContextHolder(){this.requestId = (String)MDC.get("REQUEST_ID");}public void setHeaderPropertiesInMDC(){MDC.put("REQUEST_ID", requestId);}
}public abstract class LogCallable<V> implements Callable<V> {MdcContextHolder mdcContextHolder = new MdcContextHolder();;@Overridepublic V call() throws Exception {this.preCall();V v = innerCall();this.afterCall();return v;}private void preCall(){if(mdcContextHolder!=null){mdcContextHolder.setHeaderPropertiesInMDC();}}private void afterCall(){LogUtils.clearHeaderPropertiesInMDC();}public abstract V innerCall() throws Exception;
}public abstract class LogRunnable implements Runnable{MdcContextHolder mdcContextHolder = new MdcContextHolder();;@Overridepublic void run() {this.preRun();this.innerRun();this.afterRun();}private void preRun(){if(mdcContextHolder!=null){mdcContextHolder.setHeaderPropertiesInMDC();}}private void afterRun(){LogUtils.clearHeaderPropertiesInMDC();}public abstract void innerRun();public class MdcTaskDecorator implements TaskDecorator {@Overridepublic Runnable decorate(final Runnable runnable) {LogRunnable mdcRunnable = new LogRunnable() {@Overridepublic void innerRun() {runnable.run();}};return mdcRunnable;}
}

Hessian call 之间

发送端

public class CustomHessianProxyFactory extends HessianProxyFactory {@Overridepublic Object create(Class<?> api, URL url, ClassLoader loader) {if (api == null)throw new NullPointerException("api must not be null for HessianProxyFactory.create()");InvocationHandler handler = new CustomHessianProxy(url, this, api);return Proxy.newProxyInstance(loader, new Class[] { api, HessianRemoteObject.class }, handler);}private static class CustomHessianProxy extends HessianProxy {protected CustomHessianProxy(URL url, HessianProxyFactory factory) {super(url, factory);}public CustomHessianProxy(URL url, HessianProxyFactory factory, Class<?> type) {super(url, factory, type);}@Overrideprotected void addRequestHeaders(HessianConnection conn) {super.addRequestHeaders(conn);this.addParameterInHeader(conn);}private void addParameterInHeader(HessianConnection conn){String requestId= (String) MDC.get("REQUEST_ID");conn.addHeader("REQUEST_ID", requestId);}}}

被调用端 用上面提到的logfilter 就可以了

Java Micro services: 传送唯一标识(request id)在Hessian call, rest API,JMS和Thread之间相关推荐

  1. android 通知id,java – Android:获取唯一的通知ID

    我相信你不应该一次就给用户那么多的通知.您应该显示一个整合关于Gmail客户端事件组的信息的单个通知.为此目的使用Notification.Builder. NotificationCompat.Bu ...

  2. Request Id

    调用接口返回失败,根据之前的了解,抛给了开发请求参数,希望帮助他定位问题.结果开发需要Request-ID,并指名返回值里存在.纳尼??黑人问号..后台返回null,哪来的Request-ID,于是面 ...

  3. c#获取对象的唯一标识_在 Java 中利用 redis 实现分布式全局唯一标识服务

    作者: 杨高超 juejin.im/post/5a4984265188252b145b643e 获取全局唯一标识的方法介绍 在一个IT系统中,获取一个对象的唯一标识符是一个普遍的需求.在以前的单体应用 ...

  4. 在高并发分布式情况下生成唯一标识id

    做项目的时候经常会用id作为唯一标识. 但是当有这样一个需求出现的时候:工程分布式部署,要求抗住高并发.并且生成的id是根据时间自增的.解决这个问题有很多种方法,但是要选择一个性价比比较高的策略比较不 ...

  5. 格式android id,android 获取APP的唯一标识applicationId的实例

    使用getIdentifier()方法可以方便的获各应用包下的指定资源ID. 方式一 int indentify = getResources().getIdentifier("com.te ...

  6. Java生成唯一标识码的三种方式

    Java生成唯一标识码的三种方式 前言 我们经常会遇到这样的场景,需要生成一个唯一的序列号来表明某一个数据的唯一性,在单节点的应用中我们可以简单地使用一个自增的整型来实现实现,但是在分布式情况下这个方 ...

  7. 微信用户全局唯一标识_分布式系统的唯一ID生成算法对比

    在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识. 那么如何实现全局唯一id呢?有以下几种方案. (1)方案一:独立数据库自增id 这个方案就是说你的系统每次要生成一个id,都是往一个独立库 ...

  8. React中的唯一标识key(用index VS id)和key的选择

    1. 虚拟DOM中key的作用:1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用.2). 详细的说: 当状态中的数据发生变化时,react会根据[新数据]生成[ ...

  9. python namespace unique_Python使用uuid库生成唯一标识ID

    uuid是128位的全局唯一标识符(univeral unique identifier),通常用32位的一个字符串的形式来表现.有时也称guid(global unique identifier). ...

最新文章

  1. 新学期的一些安排 | 以及一些小建议
  2. Eclipse中新建SpringBoot项目完成对json、pojo、map、list的请求
  3. 单机和分布式场景下,有哪些流控方案?
  4. 基础系列(1)-- html
  5. 西门子em235模块的功能_图文讲解PLC模拟量模块与传感器接线方法和注意事项
  6. 6、easyUI-拖放事件及应用
  7. 利用HttpWebRequest实现实体对象的上传
  8. 【code】flex_进度条样式
  9. android开发——图文并茂
  10. 数学思维游戏两则:Gabriel喇叭、世界末日论
  11. 网页扫雷(简易版)(一)
  12. SpringCloud-Learning -作者:翟永超
  13. storm 阿姆歌曲_Eminem经典歌词
  14. w7系统事件日志服务器,win7系统事件日志服务4201错误的解决方法
  15. matplotlib交互式数据光标实现——mpldatacursor
  16. java 微信时间戳转换工具_微信小程序实现时间戳格式转换
  17. 【Tools】P4V基础操作
  18. mactxt文件如何转换成html,最佳的用于Mac上的PDF文件转换到HTML文件的转换器
  19. Computer Vision_33_SIFT:TILDE: A Temporally Invariant Learned DEtector——2014
  20. docx转换为doc格式,公式变成图片问题,word2016

热门文章

  1. 谷歌帮助开发人员面向教育应用
  2. Java环境变量CLASSPATH详解(转载)
  3. 用位运算实现求绝对值-有效避开if-else判断
  4. ANT打包时记录本地版本SVN信息
  5. 虚拟化系列-VMware vSphere 5.1 虚拟机管理
  6. Android Logcat 报错:Could not create the view: For input string:
  7. HashMap的扩容机制
  8. Spring RestTemplate示例
  9. Robot Framework自动化测试框架核心指南-如何使用Java编写自定义的RobotFramework Lib
  10. 国际电汇的清算代码是什么?