原文連結:https://www.cnblogs.com/heihaozi/p/11769427.html
一年一度的雙十一購物狂歡節就要到了,又到剁手黨們開始表演的時刻了。當我們把種草很久的商品放入購物車以後,點選“結算”按鈕時,就來到了買買買必不可少的結算頁面了。讓我們虛擬一個買買買結算系統,為結算頁面提供商品、促銷、庫存等結算資訊,就此係統展開如何在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中:
@Configurationpublic 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還有很多豐富的功能,可參見官網。
分享一波我在複習過程中刷的題(含詳細答案解析)和一些學習資料,都已整理成PDF文件或者Word文件,有需要的朋友可以轉發+私信關鍵詞【面試】免費領取~
(1)最新java架構專題系列面試真題+解析(包含Kafka、Mysql、Tomcat、Docker、Spring、MyBatis、Nginx、Netty、Dubbo、Redis、Netty、Spring cloud、分散式、高併發、效能調優、微服務...)
(2)最新大廠面試真題+解析(百度,華為,騰訊,網易,迅雷...)
(3)Java學習的書籍資料