SysOperateLog

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功能

    
     

实现

在看看方法的具体实现:

    @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)