SpringAOP+自定义注解实现日志记录

 

关于自定义注解基本介绍可参考以往博客https://www.cnblogs.com/DFX339/p/11386722.html

此文主要是讲述如何通过注解标识记录日志信息,一般我们的Service接口都需要记录入参信息,参数校验,方法执行时间等

处理思路:

1.自定义注解,使用的时候通过加入注解即可注入相应的日志信息

2.使用SpringAOP, 识别注解标识的方法,切入日志信息

 

步骤一: 定义注解类 SystemLog.java 

package com.im.nexus.service.utils.logUtils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description:系统日志注解(使用在Service类里面的方法上)
 * @author: duanfeixia
 * @time: 2020/5/12 10:54
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SystemLog {
    String methoddesc() default "";//方法描述
}

 

步骤二:定义切面 SystemLogAspect.java

这里切记需要加入 @Component @Aspect 这两个注解,@Slf4j 这个注解是日志类的注解 非必选

package com.im.nexus.service.utils.logUtils;


import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义日志注解 SystemLog配合AOP注入日志信息
 */
@Component
@Aspect
@Slf4j
public class SystemLogAspect {

    // @SystemLog标识为切入点,切面会根据@SystemLog注解来注入数据
    @Pointcut("@annotation(com.imodule.nexus.service.utils.logUtils.SystemLog)")
    public void logPointCut(){
    }

    //环绕注入
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long startTime = System.currentTimeMillis();//记录目标方法的开始执行时间
        Object result = point.proceed();//执行目标方法
        long methodexecutetime = System.currentTimeMillis() - startTime;

        //日志信息记录
        try {
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            Method method = methodSignature.getMethod();
            SystemLog systemLog = method.getDeclaredAnnotation(SystemLog.class);
            String className = point.getTarget().getClass().getName();//类名
            String methodName = method.getName();//方法名

            //入参信息
            Object[] args = point.getArgs();
            List<String> list = new ArrayList<String>();
            for (Object obj : args) {
                    list.add(new Gson().toJson(obj));
            }
            log.info(className+"."+methodName+","+systemLog.methoddesc()+",入参:"+list.toString());
            log.info(className+"."+methodName+","+systemLog.methoddesc()+",耗时:"+methodexecutetime+"ms");
        } catch (Exception e) {
            log.error("日志切入出错");
        }
        return result;
    }
}

  

步骤三: 在具体Service实现类的方法上使用 @SystemLog注解

使用示例:@SystemLog(methoddesc = "方法说明内容")

package com.im.nexus.service.impl.prd;

import com.im.common.frame.exception.IMException;
import com.im.nexus.constant.NexusExceptionCodeEnum;
import com.im.nexus.dao.prd.PrdTsarateMapper;
import com.im.nexus.service.utils.BizParamCheckUtils;
import com.im.nexus.service.utils.ExceptionThrowUtils;
import com.im.nexus.service.utils.logUtils.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @description 产品接口实现类
 * @date 2020-03-31
 * @author duanfeixia
 */
@Service
@Slf4j
public class prdServiceImpl implements prdService {
    
    @Autowired
    private PrdTsarateMapper prdTsarateMapper;
    
    @Override
    @SystemLog(methoddesc = "是否简易核保-注解标识")
    public PrdResultDTO isSimple(String prdCode) throws IMException {
        //入參對象校驗
        BizParamCheckUtils.paramPropertyNullCheck("prdServiceImpl.getPrdStaticInfo:prdCode",prdCode);
        
    	PrdResultDTO prdResultDTO= new PrdResultDTO();
        try {
            Integer prdflag = prdTsarateMapper.isSimple(prdCode);
            /// 这里遵照了以前的写法,建议后续使用 1:是,0:否
            if (null != prdflag && prdflag > 0) {
                // 屬於簡易核保 : 0
            	prdResultDTO.setIsSimple(SysCnst.STR_FLAG_NO);
            } else {
                // 不屬於簡易核保 : 1
            	prdResultDTO.setIsSimple(SysCnst.STR_FLAG_YES);
            }
        } catch (Exception e) {
            log.error("prdServiceImpl.isSimple exception:[prdcode=" + prdCode + "]");
            ExceptionThrowUtils.logAndThrowException(NexusExceptionCodeEnum.EXCEPTION_DB_000001, e);
        }
        return prdResultDTO;
    }
}

  

步骤四:定义测试类,对以上方法进行测试(Junit单元测试)

package com.im.nexus.service.prd;

import com.im.common.frame.exception.IMException;
import com.im.nexus.DTO.prd.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class prdServiceTest {

    @Autowired
    private prdService prdService;

    @Test
    public void testisSimple() throws IMException{
    	try {
            PrdResultDTO prdTsarateRtl = prdService.isSimple("12");
            log.info("是否简易核保:"+prdTsarateRtl);
            log.info("prdTsarateRtl.getIsSimple:"+prdTsarateRtl.getIsSimple());
		} catch (Exception e) {
			log.error("ceshi :", e);
		}
    }
}

 

执行单元测试后,测试结果如下:

[] 2020-05-12 12:59:33:331  INFO [main] c.i.n.s.u.logUtils.SystemLogAspect 51 - com.im.nexus.service.impl.prd.prdServiceImpl.isSimple,是否简易核保-PRD,入参:["12"]
[] 2020-05-12 12:59:33:331  INFO [main] c.i.n.s.u.logUtils.SystemLogAspect 52 - com.im.nexus.service.impl.prd.prdServiceImpl.isSimple,是否简易核保-PRD,耗时:66ms
[] 2020-05-12 12:59:33:331  INFO [main] c.i.n.service.prd.prdServiceTest 26 - 是否简易核保:PrdTsarateRtl{isSimple=1}
[] 2020-05-12 12:59:33:331  INFO [main] c.i.n.service.prd.prdServiceTest 27 - prdTsarateRtl.getIsSimple:1 

前面两行则是我们通过@SystemLog注解注入的日志内容

后面两行则是我们在Service实现类的方法中手写的日志内容

  

  

 posted on 2020-05-12 13:07  阿叮339  阅读(2293)  评论(1编辑  收藏  举报