美文网首页
SysOperateLog

SysOperateLog

作者: 浮x尘 | 来源:发表于2017-06-16 15:17 被阅读105次

    SysOperateLog

    先看注解的定义:

    @Documented
    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface SysOperateLog {
        /**
         * 操作类型,取值为 com.gosun.isap.operlog.api.OperateType
         * 
         * @return 操作类型
         */
        int operateType();
    
        /**
         * 业务类型,取值为com.gosun.isap.operlog.api.ServiceType
         * 
         * @return 业务类型
         */
        int serviceType();
    
        /**
         * 操作描述
         * 
         * @return 操作描述信息
         */
        String description();
    }
    

    一个目标为方法的运行时注解,有三个数据。

    Around

    通过Spring Aop切面实现日志的记录功能,在这里主要用到了Around这个注解,该注解的意思是在目标方法运行之前和运行之后增加某些功能,可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值。
    在我们的项目中:
    @Around("within(com.gosun.isap..*) && @annotation(rl)")
    如果看不懂肯定就是因为within(com.gosun.isap..*) && @annotation(rl)这句表达式。
    下面就分析一下这句表达式的意思:
    within的官方定义是:
    within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP)
    简单的说就是匹配某个类型。

    com.gosun.isap..*
    官方例子:within(com.xyz.service..*)
    any join point (method execution only in Spring AOP) within the service package or a sub-package
    和spring的component-scan类似,递归扫描下面的包。

    @annotation的官方定义是:
    @annotation - limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation
    简单的说就是只匹配拥有某个注解的方法。

    上面两个条件用&&连接起来意思就很清楚了,切入com.gosun.isap下的包,并且在类方法包含SysOperateLog注解的情况下,增加日志功能。

    Spring

    在spring配置文件中添加配置启用Aop功能

        <context:component-scan base-package="com.gosun.isap.operlog"></context:component-scan>
        <aop:aspectj-autoproxy/> 
    

    实现

    在看看方法的具体实现:

        @Around("within(com.gosun.isap..*) && @annotation(rl)")
        public Object writeOperateLog(ProceedingJoinPoint jp, SysOperateLog rl) throws Throwable {
            String className = jp.getTarget().getClass().toString();// 获取目标类名
            className = className.substring(className.indexOf("com"));
            String signature = jp.getSignature().toString();// 获取目标方法签名
            String methodName = signature.substring(signature.lastIndexOf(".") + 1, signature.indexOf("("));
            Object[] parames = jp.getArgs();// 获取目标方法体参数
            String params = parseParames(parames); // 解析目标方法体的参数
    
            int serviceType = rl.serviceType();
            int operateType = rl.operateType();
            String description = rl.description();
    
            StringBuilder sbLogDetail = new StringBuilder();
            sbLogDetail.append(description).append(", 参数为:").append(params);
    
            Object object;
            try {
                object = jp.proceed();
                if (object != null && object instanceof ResponseResult) {
                    int code = ((ResponseResult) object).getHead().getErrorCode();
                    if (code == ErrorCode.ERR_OK) {
                        success(serviceType, operateType, sbLogDetail.toString());
                    } else {
                        failed(serviceType, operateType, sbLogDetail.toString(),
                                ((ResponseResult) object).getHead().getMessage());
                    }
                } else {
                    success(serviceType, operateType, sbLogDetail.toString());
                }
            } catch (Throwable throwable) {
                failed(serviceType, operateType, sbLogDetail.toString(), throwable.getMessage());
                throw throwable;
            }
            return object;
        }
    
        private void success(int serviceType, int operateType, String description) {
            try {
                OperateLogWriter.success(serviceType, operateType, description);
            } catch (Exception e) {
                logger.error("Write operate log error ", e);
            }
        }
    
        private void failed(int serviceType, int operateType, String description, String reason) {
            try {
                OperateLogWriter.fail(serviceType, operateType, description, reason);
            } catch (Exception e) {
                logger.error("Write operate log error ", e);
            }
        }
    

    可以看到不管是成功还是失败,最终依旧调用了OperateLogWriter去写日志,但通过AOP的方式解耦了分散在业务逻辑中的写日志代码。
    在这里object = jp.proceed();才真正的执行了我们的方法,并通过返回的对象int code = ((ResponseResult) object).getHead().getErrorCode();判断方法的成功与失败,然后写入日志。

    int serviceType = rl.serviceType();
    int operateType = rl.operateType();
    String description = rl.description();
    

    这三句话将注解中的内容提取出来写入日志中,因此这个注解的使用也非常简单:

    @SysOperateLog(serviceType = ServiceType.CONFIG_RES, operateType = OperateType.CONFIG_ADD, description = "添加时间模板")
    

    最终这些元数据都会写入到日志中。

    相关文章

      网友评论

          本文标题:SysOperateLog

          本文链接:https://www.haomeiwen.com/subject/tdqmqxtx.html