五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
买买买结算系统

一年一度的双十一购物狂欢节就要到了,又到剁手党们开始表演的时刻了。当我们把种草很久的商品放入购物车以后,点击“结算”按钮时,就来到了买买买必不可少的结算页面了。让我们虚拟一个买买买结算系统,为结算页面提供商品、促销、库存等结算信息,就此系统展开如何在SpringBoot项目中集成CAT调用链。买买买结算系统包含以下4个项目:
- 结算UI:为前端页面提供结算的基础数据。
- 购物车API:获取用户购物车中有哪些商品。
- 商品API:获取商品详细信息
- 商品促销API:获取商品的促销信息
- 商品库存API:获取商品的库存信息
时序图如下:

通过Maven添加依赖
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-client</artifactId>
<version>3.0.0</version>
</dependency>
配置client.xml
创建/data/appdatas/cat/目录,并创建client.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<servers>
<server ip="127.0.0.1" port="2280" http-port="8080" />
</servers>
</config>
注意:把127.0.0.1替换成CAT服务端的IP。
配置项目名称
买买买结算系统中一共有5个项目,每个项目都需要配置各自的项目名称。
首先,在每个项目中创建如下文件:
src/main/resources/META-INF/app.properties
然后,在每个项目里添加如下内容:
- 结算UI:
app.name=buy-buy-buy-checkout - 购物车API:
app.name=buy-buy-buy-cart - 商品API:
app.name=buy-buy-buy-product - 商品促销API:
app.name=buy-buy-buy-promotion - 商品库存API:
app.name=buy-buy-buy-store
注意:项目名称只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (_) 和中划线 (-)
准备埋点
在埋点之前,需要先写两个公共类,方便之后埋点时调用。
- 第一个类实现Cat.Context接口,用于存放调用链上下文信息:
public class CatContext implements Cat.Context {
private Map<String, String> properties = new HashMap<>();
@Override
public void addProperty(String key, String value) {
properties.put(key, value);
}
@Override
public String getProperty(String key) {
return properties.get(key);
}
@Override
public String toString() {
return "CatContext{"
+ "properties=" + properties + '}';
}
}
- 第二个类中定义一些常量,在调用API时作为header中的key。
public class CatHttpConstants {
public static final String CAT_HTTP_HEADER_CHILD_MESSAGE_ID = "DD-CAT-CHILD-MESSAGE-ID";
public static final String CAT_HTTP_HEADER_PARENT_MESSAGE_ID = "DD-CAT-PARENT-MESSAGE-ID";
public static final String CAT_HTTP_HEADER_ROOT_MESSAGE_ID = "DD-CAT-ROOT-MESSAGE-ID";
}
开始埋点
使用CAT进行分布式调用链监控,需要修改项目中的代码进行埋点:
- 在刚刚接收到请求时进行埋点。
- 在准备调用API时进行埋点。
那么在买买买结算系统中需要做哪些代码修改呢?看一下时序图的变化就明白了:

第一个埋点,在刚刚接收到请求时,这里使用Filter实现,代码如下:
public class CatServletFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
CatContext catContext = new CatContext();
catContext.addProperty(Cat.Context.ROOT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));
catContext.addProperty(Cat.Context.PARENT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));
catContext.addProperty(Cat.Context.CHILD, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));
Cat.logRemoteCallServer(catContext);
Transaction t = Cat.newTransaction(CatConstants.TYPE_URL, request.getRequestURI());
try {
Cat.logEvent("Service.method", request.getMethod(), Message.SUCCESS, request.getRequestURL().toString());
Cat.logEvent("Service.client", request.getRemoteHost());
filterChain.doFilter(servletRequest, servletResponse);
t.setStatus(Transaction.SUCCESS);
} catch (Exception ex) {
t.setStatus(ex);
Cat.logError(ex);
throw ex;
} finally {
t.complete();
}
}
@Override
public void destroy() {
}
}
Filter已经写好了,接下来还需要把Filter注册到SpringBoot中:
@Configuration
public class CatConfiguration {
@Bean
public FilterRegistrationBean catServletFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
CatServletFilter filter = new CatServletFilter();
registration.setFilter(filter);
registration.addUrlPatterns("/*");
registration.setName("cat-servlet-filter");
registration.setOrder(1);
return registration;
}
}
第两个埋点,在调用API的HttpClient工具类中统一增加代码,以GET方式为例:
public static String doGet(String url) throws IOException {
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
String content = null;
Transaction t = Cat.newTransaction(CatConstants.TYPE_CALL, url);
try {
Context ctx = new CatContext();
Cat.logRemoteCallClient(ctx);
httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID, ctx.getProperty(Cat.Context.ROOT));
httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID, ctx.getProperty(Cat.Context.PARENT));
httpGet.setHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID, ctx.getProperty(Cat.Context.CHILD));
response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
content = EntityUtils.toString(response.getEntity(), "UTF-8");
t.setStatus(Transaction.SUCCESS);
}
} catch (Exception e) {
Cat.logError(e);
t.setStatus(e);
throw e;
} finally {
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
t.complete();
}
return content;
}
结语
以上便是SpringBoot集成CAT调用链的整个实例了,可以灵活应用,更加优雅的集成到实际项目中。
另外,CAT还有很多丰富的功能,可参见官网。
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链的更多相关文章
- SpringBoot12 QueryDSL01之QueryDSL介绍、springBoot项目中集成QueryDSL
1 QueryDSL介绍 1.1 背景 QueryDSL的诞生解决了HQL查询类型安全方面的缺陷:HQL查询的扩展需要用字符串拼接的方式进行,这往往会导致代码的阅读困难:通过字符串对域类型和属性的不安 ...
- SpringBoot项目中遇到的BUG
1.启动项目的时候报错 1.Error starting ApplicationContext. To display the auto-configuration report re-run you ...
- SpringBoot项目中,表单的验证操作
在创建Springboot项目中,我们使用了表单验证操作,这一操作将极大地简化我们编程的开发 1.接收数据,以及验证 @PostMapping("/save") public Mo ...
- 国际化的实现i18n--错误码国际化以及在springboot项目中使用
国际化 ,英文叫 internationalization 单词太长 ,又被简称为 i18n(取头取尾中间有18个字母); 主要涉及3个类: Locale用来设置定制的语言和国家代码 Resource ...
- Spring-Boot项目中配置redis注解缓存
Spring-Boot项目中配置redis注解缓存 在pom中添加redis缓存支持依赖 <dependency> <groupId>org.springframework.b ...
- 在SpringBoot项目中添加logback的MDC
在SpringBoot项目中添加logback的MDC 先看下MDC是什么 Mapped Diagnostic Context,用于打LOG时跟踪一个“会话“.一个”事务“.举例,有一个web ...
- 自身使用的springboot项目中比较全的pom.xml
在学习的时候常建新的项目,mark下商用的jar <dependency> <groupId>org.mybatis</groupId> <artifactI ...
- springboot 项目中获取默认注入的序列化对象 ObjectMapper
在 springboot 项目中使用 @SpringBootApplication 会自动标记 @EnableAutoConfiguration 在接口中经常需要使用时间类型,Date ,如果想要格式 ...
- springboot项目中js、css静态文件路径访问
springboot静态文件访问的问题,相信大家也有遇到这个问题,如下图项目结构. 项目结构如上所示,静态页面引入js.css如下所示. 大家肯定都是这样写的,但是运行的话就是出不来效果,图片也不显示 ...
随机推荐
- JavaScript之数学对象Math
Javascript 中Math和其他对象不同,它具有数学常数和函数的属性和方法.因为它的属性是数学常数,所以不能被改变(可以进行赋值操作,但最后值不变). Math的方法就是普通函数,调用他们直接用 ...
- NET Core 3.0 新姿势 将AutoFac替换内置DI
.NET Core 3.0 和 以往版本不同,替换AutoFac服务的方式有了一定的变化,在尝试着升级项目的时候出现了一些问题. 原来在NET Core 2.1时候,AutoFac返回一个 IServ ...
- 23种设计模式之责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式. ...
- j2ee开发之Spring2.5框架学习笔记
Spring 2.5框架学习笔记 1.是一个开源的控制反转IOC和面向切面AOP的容器框架 2.IOC控制反转 public class PersonServiceBean { private Per ...
- 【ADO.NET基础-Login】带验证码验证的登录界面(用于简单的基础学习)
以下代码如果有不对或者不妥之处,还望大神们指点一二 或者有同学者有问题或建议,一定要提出来,共同探讨 小弟在此感谢! 前台代码: <!DOCTYPE html> <html xmln ...
- .net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联
Signalr是以Group.Connect为核心来进行推送,比如,给某个组.某个连接来推送,但实际场景中,核心应该是某个组.某个人:然而一个人可以对应多个连接(浏览器多个tab页):本节就来介绍下自 ...
- useradd、id、userdel、usermod、chsh、passwd、pwck
1.useradd [-cdefgGmkMsu] 用户名称 用来添加用户 -c “备注“:加上备注文字 -d 路径:指定家目录 -e 有效期限:指定帐号的有效期限: -f 缓冲天数:指定在密码过期后多 ...
- CSS3自定义浏览器滚动条样式
一个完整滚动条右以下部分组成: ::-webkit-scrollbar 滚动条整体部分,常用属性:width,height,background,border: ::-webkit-scrollbar ...
- 向net core 3.0进击——April.WebApi从2.2爬到3.0
目录 前言 升级之路 测试 小结 前言 在之前对Swagger的变化做了调整后,就开始想着要不把之前的工程升级得了,这样就还是个demo工程,来做各种测试(当然还是因为懒),这就有了今天这个比较折腾的 ...
- MySQL系统表的利用姿势(浅探)
MySQL数据库文件读写 权限要求: 具备读写权限并且目标文件为可读内容 目标内容具有完整路径且目录可访问 目标内容是否具备文件读写操作权限 查看是否有文件读写权限 show variables li ...