在上一篇中,我們採用resttemplate+ribbon進行後端服務的請求,做數據聚合,但是卻發現自定義的請求並沒有日誌,接下來我們需要做請求日誌的記錄及加入斷路器。
關於日誌,我們採用切面來做
日誌切面類LogAspect:
/**
* All rights Reserved, Designed By OprCalf
* Copyright: Copyright(C) 2016-2020
* Company OprCalf Ltd.
*/
package com.platform.gateway.common.aspect;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.extern.apachecommons.CommonsLog;
/**@projectName: platform-gateway
* @package: com.platform.gateway.common.aspect
* @className: LogAspect.java
* @description: 日誌切面
* @author: OprCalf
* @date: 2019年5月22日
*/
@Component
@Aspect
@CommonsLog
public class LogAspect {
@Autowired
private HttpServletRequest request;
@Pointcut("execution( * com.platform.*.agg..*Controller.*(..))")
public void logPointCut() {
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 記錄下請求內容
log.info("請求地址 : " + request.getRequestURL().toString());
log.info("請求方法 : " + request.getMethod());
log.info("類方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
log.info("參數 : " + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(returning = "ret", pointcut = "logPointCut()")
public void doAfterReturning(Object ret) throws Throwable {
// 處理完請求,返回內容(返回值太複雜時,打印的是物理存儲空間的地址)
log.info("返回值 : " + ret);
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
final long startTime = System.currentTimeMillis();
// ob 爲方法的返回值
final Object ob = pjp.proceed();
log.info("耗時 : " + (System.currentTimeMillis() - startTime));
return ob;
}
}
這樣子就完成了,待會我們來實驗一下,接下來增加斷路器,直接在GetRequest類上新增,更改後的代碼如下
/**
* All rights Reserved, Designed By OprCalf
* Copyright: Copyright(C) 2016-2020
* Company LengYin Ltd.
*/
package com.platform.gateway.common.request;
import javax.annotation.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.platform.gateway.common.utils.MsgUtils;
/**
* @projectName: platform-gateway
* @package: com.platform.gateway.common.request
* @className: GetRequest.java
* @description: Get請求
* @author: OprCalf
* @date: 2020年3月27日
*/
@Service
@SuppressWarnings("deprecation")
public class GetRequest extends Request {
@Resource(name = "balanceTemplate")
private RestTemplate balanceTemplate;
@Resource(name = "singleTemplate")
private RestTemplate singleTemplate;
/**
* 發送請求到服務端,初始化head裏面的user爲空
* @author OprCalf
* @param serviceAdd
* @param servicePath
* @param params
* @return JSONObject
*/
@HystrixCommand(fallbackMethod = "failNullUserForJson")
public JSONObject getNullUserForJson(String serviceAdd, String servicePath) {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
final HttpEntity<Object> requestEntity = new HttpEntity<>("", headers);
final ResponseEntity<JSONObject> response = balanceTemplate.exchange(serviceAdd + servicePath, HttpMethod.GET,
requestEntity,
JSONObject.class);
return JSONObject.parseObject(JSONObject.toJSONString(response.getBody(), Request.filter));
}
/**
* 斷路器:發送請求到服務端,初始化head裏面的user爲空
* @author OprCalf
* @date 2019年5月22日
* @return String
*/
public JSONObject failNullUserForJson(String serviceAdd, String servicePath) {
return JSON.parseObject(returnError("請求超時,請稍後再試...").toString());
}
}
Request類更改,代碼如下:
/**
* All rights Reserved, Designed By OprCalf
* Copyright: Copyright(C) 2016-2020
* Company LengYin Ltd.
*/
package com.platform.gateway.common.request;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.ValueFilter;
import lombok.extern.slf4j.Slf4j;
/**
* @projectName: platform-gateway
* @package: com.platform.gateway.common.request
* @className: Request.java
* @description: 請求設置
* @author: OprCalf
* @date: 2020年3月27日
*/
@Service
@Slf4j
public class Request {
@Autowired
private HttpServletRequest request;
/**
* 重寫FastJson的值過濾,當爲空值的時候返回"",不然轉字符串會直接把屬性過濾掉
* @author OprCalf
*/
public static ValueFilter filter = (obj, s, v) -> {
if (v == null) {
return "";
}
return v;
};
/**
* 初始化web的請求頭信息
* @author OprCalf
* @param needUser
* @return HttpHeaders
*/
public HttpHeaders initWebHeader() {
try {
final String access_token = request.getHeader("access_token");
final HttpHeaders headers = new HttpHeaders();
headers.add("access_token", access_token);
return headers;
}
catch (final Exception e) {
log.error("{}", e.fillInStackTrace());
return new HttpHeaders();
}
}
/**
* 返回錯誤信息
* @author OprCalf
* @param result
* @return JSONObject
*/
public static JSONObject returnError(Object result) {
final JSONObject json = new JSONObject();
final JSONObject data = new JSONObject();
json.put("respStatus", "01");
json.put("respDesc", result);
json.put("data", data);
return json;
}
/**
* 返回正確的信息
* @author OprCalf
* @param successMsg
* @param data
* @return String
*/
public static JSONObject returnSuccess(String successMsg, Object data) {
final JSONObject json = new JSONObject();
json.put("respStatus", "00");
json.put("respDesc", successMsg);
json.put("data", data);
return json;
}
}
完成了,我們開始測試一下
日誌測試:直接調用接口
調用成功,有日誌出來。
斷路測試:停掉後端服務
返回我們需要的信息,至此聚合服務整合日誌,斷路器完成。
最後,謝謝觀賞,覺得好的話,點個贊,有什麼問題可以留言溝通,麼麼噠。