AOP中ProceedingJoinPoint获取目标方法,参数,注解

private void saveLog(ProceedingJoinPoint jp,long time)throws Throwable {
            package com.cy.pj.common.aspect;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.util.IPUtils;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;

import lombok.extern.slf4j.Slf4j;
/**
 * @Aspect 描述的类为切面类,此类中实现:
 * 1)切入点(Pointcut)的定义
 * 2)通知(advice)的定义(扩展功能)
 */
@Slf4j
@Aspect
@Component
public class SysLogAspect {
     /**
      * @Pointcut 注解用于描述或定义一个切入点
        *  切入点的定义需要遵循spring中指定的表达式规范
        例如:("bean(sysMenuServiceImpl)")为切入点表达式
        的一种定义方式。
      */
     //bean(bean名称或一个表达式)
     //@Pointcut("bean(sysMenuServiceImpl)")
     @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
     public void logPointCut() {}
     
     /**
      * @Around 注解描述的方法为一个环绕通知方法,
            * 在此方法中可以添加扩展业务逻辑,可以调用下一个
              切面对象或目标方法
      * @param jp 连接点(此连接点只应用@Around描述的方法)
      * @return
      * @throws Throwable
      */
     @Around("logPointCut()")
     public Object aroundAdvice(ProceedingJoinPoint jp)
     throws Throwable{
         long start=System.currentTimeMillis();
         log.info("start:"+start);
         Object result=jp.proceed();//调用下一个切面或目标方法
         long end=System.currentTimeMillis();
         log.info("end:"+end);
         //记录日志(用户行为信息)
         saveLog(jp,(end-start));
         return result;
     }
     @Autowired
     private SysLogService sysLogService;
     //日志记录
     private void saveLog(ProceedingJoinPoint jp,long time)throws Throwable {
         //1.获取用户行为日志(ip,username,operation,method,params,time,createdTime)
         //获取类的字节码对象,通过字节码对象获取方法信息
         Class<?> targetCls=jp.getTarget().getClass();
         //获取方法签名(通过此签名获取目标方法信息)
         MethodSignature ms=(MethodSignature)jp.getSignature();
         //获取目标方法上的注解指定的操作名称
         Method targetMethod=
         targetCls.getDeclaredMethod(
                 ms.getName(),
                 ms.getParameterTypes());
         RequiredLog requiredLog=
         targetMethod.getAnnotation(RequiredLog.class);
         String operation=requiredLog.value();
         System.out.println("targetMethod="+targetMethod);
         //获取目标方法名(目标类型+方法名)
         String targetClsName=targetCls.getName();
         String targetObjectMethodName=targetClsName+"."+ms.getName();
         //获取请求参数
         String targetMethodParams=Arrays.toString(jp.getArgs());
         //2.封装用户行为日志(SysLog)
         SysLog entity=new SysLog();
         entity.setIp(IPUtils.getIpAddr());
         entity.setUsername("admin");
         entity.setOperation(operation);
         entity.setMethod(targetObjectMethodName);
         entity.setParams(targetMethodParams);
         entity.setTime(time);
         entity.setCreatedTime(new Date());
         //3.调用业务层对象方法(saveObject)将日志写入到数据库
         sysLogService.saveObject(entity);
     }
}
    }

 https://www.yuque.com/binarylei/java/annotation

posted @ 2020-11-23 17:43  edda_huang  阅读(13543)  评论(0编辑  收藏  举报