买买买结算系统

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

  1. 结算UI:为前端页面提供结算的基础数据。
  2. 购物车API:获取用户购物车中有哪些商品。
  3. 商品API:获取商品详细信息
  4. 商品促销API:获取商品的促销信息
  5. 商品库存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

然后,在每个项目里添加如下内容:

  1. 结算UI:

    app.name=buy-buy-buy-checkout
  2. 购物车API:

    app.name=buy-buy-buy-cart
  3. 商品API:

    app.name=buy-buy-buy-product
  4. 商品促销API:

    app.name=buy-buy-buy-promotion
  5. 商品库存API:

    app.name=buy-buy-buy-store

注意:项目名称只能包含英文字母 (a-z, A-Z)、数字 (0-9)、下划线 (_) 和中划线 (-)

准备埋点

在埋点之前,需要先写两个公共类,方便之后埋点时调用。

  1. 第一个类实现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 + '}';
}
}
  1. 第二个类中定义一些常量,在调用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进行分布式调用链监控,需要修改项目中的代码进行埋点:

  1. 在刚刚接收到请求时进行埋点。
  2. 在准备调用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调用链的更多相关文章

  1. SpringBoot12 QueryDSL01之QueryDSL介绍、springBoot项目中集成QueryDSL

    1 QueryDSL介绍 1.1 背景 QueryDSL的诞生解决了HQL查询类型安全方面的缺陷:HQL查询的扩展需要用字符串拼接的方式进行,这往往会导致代码的阅读困难:通过字符串对域类型和属性的不安 ...

  2. SpringBoot项目中遇到的BUG

    1.启动项目的时候报错 1.Error starting ApplicationContext. To display the auto-configuration report re-run you ...

  3. SpringBoot项目中,表单的验证操作

    在创建Springboot项目中,我们使用了表单验证操作,这一操作将极大地简化我们编程的开发 1.接收数据,以及验证 @PostMapping("/save") public Mo ...

  4. 国际化的实现i18n--错误码国际化以及在springboot项目中使用

    国际化 ,英文叫 internationalization 单词太长 ,又被简称为 i18n(取头取尾中间有18个字母); 主要涉及3个类: Locale用来设置定制的语言和国家代码 Resource ...

  5. Spring-Boot项目中配置redis注解缓存

    Spring-Boot项目中配置redis注解缓存 在pom中添加redis缓存支持依赖 <dependency> <groupId>org.springframework.b ...

  6. 在SpringBoot项目中添加logback的MDC

    在SpringBoot项目中添加logback的MDC     先看下MDC是什么 Mapped Diagnostic Context,用于打LOG时跟踪一个“会话“.一个”事务“.举例,有一个web ...

  7. 自身使用的springboot项目中比较全的pom.xml

    在学习的时候常建新的项目,mark下商用的jar <dependency> <groupId>org.mybatis</groupId> <artifactI ...

  8. springboot 项目中获取默认注入的序列化对象 ObjectMapper

    在 springboot 项目中使用 @SpringBootApplication 会自动标记 @EnableAutoConfiguration 在接口中经常需要使用时间类型,Date ,如果想要格式 ...

  9. springboot项目中js、css静态文件路径访问

    springboot静态文件访问的问题,相信大家也有遇到这个问题,如下图项目结构. 项目结构如上所示,静态页面引入js.css如下所示. 大家肯定都是这样写的,但是运行的话就是出不来效果,图片也不显示 ...

随机推荐

  1. maven仓库 - nexus配置

    搭建环境: 腾讯云服务器 CentOS 6.8.jdk7.sonatype nexus.maven.Xshell 5 版本信息: jdk : jdk-7u80-linux-x64.tar.gz nex ...

  2. java中的逃逸分析

    逃逸分析 public static StringBuffer craeteStringBuffer(String s1, String s2) { StringBuffer sb = new Str ...

  3. 【linux】【docker】docker及docker-compose安装

    安装 一. docker安装 Centos 安装docker18.03 wget https://download.docker.com/linux/centos/7/x86_64/stable/Pa ...

  4. redis-分片(转)

    转:https://www.cnblogs.com/houziwty/p/5167075.html 分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,这样每个实例将只包 ...

  5. layui table异步调用数据的时候,数据展示不出来现象解决方案

    最近使用layui table进行异步获取数据并填充的时候,控制台打印出数据长度为0,但是其中还有数据,网上找了很多办法,下边是我最后使用的. 一般,render渲染表格是独立的书写格式,但是我在做数 ...

  6. Flask基础(16)-->WTForms表单创建和简单验证

    Flask基础(16)-->WTForms表单创建和简单验证 前言:使用Flask_WTF需要配置参数SECRET_KEYCSRF_ENABLED是为了CSRF(跨站请求伪造)保护.SECRET ...

  7. ORM增删改查

    目录 orm django 连接mysql顺序 1 settings配置文件中 2 项目文件夹下的init文件中写上下面内容, 补充 3 models文件中创建一个类(类名就是表名) 4.执行数据库同 ...

  8. Java 学习笔记之 Synchronized锁重入

    Synchronized锁重入: 当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁.这也证明在一个Synchronized方法/块的内部调用本类的其他Synchronized方法 ...

  9. Hadoop 学习笔记之 Incompatible namespaceIDs问题

    Hadoop重新格式化后,仍然datanode启动失败,查看log: org.apache.hadoop.hdfs.server.datanode.DataNode: Java.io.IOExcept ...

  10. 六、springboot 简单优雅是实现短信服务

    前言 上一篇讲了 springboot 集成邮件服务,接下来让我们一起学习下springboot项目中怎么使用短信服务吧. 项目中的短信服务基本上上都会用到,简单的注册验证码,消息通知等等都会用到.所 ...