共计 4532 个字符,预计需要花费 12 分钟才能阅读完成。
买买买结算零碎
一年一度的双十一购物狂欢节就要到了,又到剁手党们开始表演的时刻了。当咱们把种草很久的商品放入购物车当前,点击“结算”按钮时,就来到了买买买必不可少的结算页面了。让咱们虚构一个 买买买结算零碎 ,为结算页面提供商品、促销、库存等结算信息,就此零碎开展如何在 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_URL, 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 还有很多丰盛的性能,可参见官网。