技术标签: spring java aop 工作总结 log4j
项目中经常会看到在所有的Rpc接口实现中记录请求参数,以及try catch,每个方法都来一次,看着就不舒服,类似下面这段代码
public CloudServerResponse<Boolean> updateExpressInfo(SendAppraisalExpressParam sendAppraisalExpressParam) {
log.info("updateExpressInfo:{}",JSON.toJSONString(sendAppraisalExpressParam));
CloudServerResponse<Boolean> cloudServerResponse = new CloudServerResponse<>();
try{
int i = this.updateExpress(sendAppraisalExpressParam);
return cloudServerResponse.setResult(i>=1);
}catch (Exception e){
log.error("AppraisalLogisticService.updateExpressInfo:{}",e);
return cloudServerResponse;
}
}
public CloudServerResponse<Boolean> updateExpressInfo(SendAppraisalExpressParam sendAppraisalExpressParam) {
CloudServerResponse<Boolean> cloudServerResponse = new CloudServerResponse<>();
int i = this.updateExpress(sendAppraisalExpressParam);
return cloudServerResponse.setResult(i>=1);
}
是不是清爽多了:)
@Aspect
@Slf4j
@Configuration
@ConditionalOnProperty(name = "wwdz.rpc.service.log.enabled")
public class DubboServiceAspect {
/**
* 返回值类型为Response的Service
*/
@Pointcut("@within(org.apache.dubbo.config.annotation.Service) && execution(public com.wwdz.mall.common.vo.response.CloudServerResponse com.wwdz..*.*(..))")
private void servicePointcut() {
}
/**
* 任何持有@Transactional注解的方法
*/
@Pointcut(value = "@annotation(org.springframework.transaction.annotation.Transactional)")
private void transactionalPointcut() {
}
/**
* 异常处理切面
* 将异常包装为Response,避免dubbo进行包装
*
* @param pjp 处理点
* @return Object
*/
@Around("servicePointcut() && !transactionalPointcut()")
public Object doAround(ProceedingJoinPoint pjp) {
Object[] args = pjp.getArgs();
Long currentTimeMillis = System.currentTimeMillis();
try {
Object result = pjp.proceed();
processSuccessfulLog(pjp, args, result, currentTimeMillis);
return result;
} catch (BizException e) {
// 业务自定义异常
CloudServerResponse cloudServerResponse = e.createResponse();
processSuccessfulLog(pjp, args, cloudServerResponse, currentTimeMillis);
return cloudServerResponse;
}
catch (Throwable e) {
processException(pjp, args, e, currentTimeMillis);
return CloudResultCode.INTERAL_ERROR.createResponse();
}
}
/**
* 记录请求成功日志
* @param joinPoint
* @param args
* @param result
* @param startCurrentTimeMillis
*/
private void processSuccessfulLog(ProceedingJoinPoint joinPoint, Object[] args, Object result, Long startCurrentTimeMillis) {
MethodSignature methodSign = (MethodSignature)joinPoint.getSignature();
UnLog unLog = methodSign.getMethod().getAnnotation(UnLog.class);
StringBuilder logMsg = new StringBuilder();
logMsg.append(logServiceMsg(joinPoint));
logMsg.append(logArgs(args));
logMsg.append(logResponse(result));
logMsg.append(logTimeMillis(startCurrentTimeMillis));
if(unLog == null){
log.info(logMsg.toString());
}
}
/**
* 任何持有@Transactional注解的方法异常处理切面
* 将自定义的业务异常转为RuntimeException:
* 1.规避dubbo的包装,让customer可以正常获取message
* 2.抛出RuntimeException使事务可以正确回滚
* 其他异常不处理
*
* @param pjp 处理点
* @return Object
*/
@Around("servicePointcut() && transactionalPointcut()")
public Object doTransactionalAround(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} catch (Throwable e) {
// dubbo会将异常捕获进行打印,这里就不打印了
// processException(pjp, args, e);
throw new RuntimeException(e.getMessage());
}
}
/**
* 处理异常
* @param joinPoint 切点
* @param args 参数
* @param throwable 异常
* @param startCurrentTimeMillis
*/
private void processException(final ProceedingJoinPoint joinPoint, final Object[] args, Throwable throwable, Long startCurrentTimeMillis) {
StringBuilder logMsg = new StringBuilder();
logMsg.append(logServiceMsg(joinPoint));
logMsg.append(logArgs(args));
logMsg.append(logTimeMillis(startCurrentTimeMillis));
log.error(logMsg.toString(), throwable);
}
/**
* 拼接入参
* @param args
* @return
*/
private String logArgs(Object[] args){
if(args == null || args.length <= 0){
return "Request: No request param\n";
}
List<Object> usableArgs = new ArrayList<>();
Collections.addAll(usableArgs, args);
return "Request: " + JSONObject.toJSONString(usableArgs) + "\n";
}
/**
* 拼接出参
* @param retVal
* @return
*/
private String logResponse(Object retVal) {
return "Response: " + JSONObject.toJSONString(retVal) + "\n";
}
/**
* 拼接服务接口信息
* @param joinPoint
* @return
*/
private String logServiceMsg(final ProceedingJoinPoint joinPoint){
return "Service: " + joinPoint.toLongString() + "\n";
}
/**
* 拼接执行时间
* @param startCurrentTimeMillis
* @return
*/
private String logTimeMillis(long startCurrentTimeMillis){
return "TimeMillis: " + (System.currentTimeMillis() - startCurrentTimeMillis) + "\n";
}
}
以上代码注解应该挺清楚,代码也比较简单,使用的时候注意要在配置中添加一下,默认是不开启的
wwdz.rpc.service.log.enabled = true
还有一点要注意,假如有一些请求入参或者请求结果很大,日志文件可能会暴涨,这种情况下如果确定这个日志没有太大的价值,可以在方法上加@Unlog注解,屏蔽这个方法的日志
/**
* 注解加上后不打请求日志
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UnLog {
}
执行一下,看看日志打印的结果:
服务名service
入参request
结果response
耗时TimeMillis
都打出来了
异常日志
方法主体: /** * 递归获取每个JSONObject的最后一个节点的key与value * 如果遇到相等的key,则key为'key=>value'执行时保存 。或在后一个key值拼接随机种子 * 为以后处理JSON的主要工具类 * 开发日期:2014-7-10 16:41 * * @author mengfeiyang * @param o
译文部分Linux C下printf 和wprintf混用,仅一个有效果,另一个写返回-1.无errno信息,但是写失败。问题解答链接https://stackoverflow.com/questions/26816547/whats-the-difference-between-printfs-printfls-wprintfs-and-wp标准解析链接https://en.cppreferen...
Spring Boot 项目结构介绍 1 POM 文件 1.1 继承<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-start...
今天在打包springboot项目的时候遇到该报错解决1:在pom加上<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-s...
为什么80%的码农都做不了架构师?>>> ...
机器学习中的调参前言1、随机搜索和网格搜索2、 遗传算法前言超参数调优是机器学习中的重要一环,拿随机森林算法而言,树的个数,数的深度,剪枝参数等等需要找到最优的参数组合,超参数较少时,我们可以采用for循环遍历所有参数的可能组合,但参数很多时,最优参数的搜寻将会变得困难,本文介绍了几种常用的调参方法,后续如果学到还会更新其他调参算法。其中网格搜索法和随机搜索法采用的是sklearn中的GridSearchCV类和RandomizedSearchCV类,所用实例的数据集点击这下载,数据集为爱荷华州住房数据
1、超时原因外部网站,国内访问时可能会超时fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz2、解决方法修改Dockerfile,使用国内的alpine源2.1、正确的做法正确的做法是使用国内源完全覆盖 /etc/apk/repositories在Dockerfile中增加下面的第二行FROM alpine:3.7RUN echo -e http://mirrors.ustc.edu.cn
第2章 Linux&Unixbooting bootstrappingmonolithic kernelmicrokernel serveGUI graphical user interface非盈利版权 Copyleft GPL general public license 发行版 distribution (dist
开发时,偶尔会遇到需要的jar包,明明maven仓库中心有,但就是载不下来,需要我们从仓库中心,下载后,将jar包添加进本地的仓库中,供项目总的pom文件引用。 1. 从maven仓库中心或者是其他途径下载我们所需要的jar包 2. 在文本编辑器中,提前编辑好以下命令,根据jar包实际情况替换对应的变量mvn install:install-file "-Dfile=本地jar包所在路径" "-DgroupId=设置groupId" "-Darti...
文章目录1 字符与字符串的相互转换1.1 将字符数组转为字符串1.2 将字符串转为字符数组1.3 将字符串转为单个字符1.4 判断一个字符串是否由数字组成?2 字节与字符串的相互转换2.1 将字节数组转为字符串2.2 将字符串转为字节数组3 字符串比较3.1 不区分大小相等比较3.2 比较两个字符串的大小4 字符串查找4.1 判断字符串在源字符串中是否存在4.2 判断字符串是否以指定的字符串开始4...
原本想使用VMWare来运行X86版本的QNX7.0系统,但是运行起来之后,没法输入。 虽然QNX官方有提供现成的QNX VMware镜像,但那不是我需要的东西,所以参照官方的QNX VMware镜像,根据它的启动脚本, 我将标准的QNX X86 BSP包中编译和启动脚本x86_64-denverton.build文件进行了修改,针对VMware的特殊情况,使用了devh-ps2ser-vm.s...