0
点赞
收藏
分享

微信扫一扫

#yyds干货盘点# 利用aop记录日志,aop失效问题以及解决方法和原因,aop重复执行方法可能的原因


首先是aop的基础使用

//声明注解
@Inherited
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {
String value() default "";
}


//声明advice
@Component
@Aspect
@Slf4j
public class OperateAdvice {

@Around("execution(* *(..)) && @annotation(operateLog) ")
public Object insertLogAround(ProceedingJoinPoint pjp , OperateLog operateLog)
throws Throwable{
System.out.println(" ************************ 记录日志 [start] ****************************** ");
MineStrategyLog op = new MineStrategyLog(); //记录日志的实体类
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
op.setOperateTime(sdf.format(new Date()));
op.setOperateUser("操作人"); // 操作人
op.setOperateClass(pjp.getTarget().getClass().getName());// 操作的类
op.setOperateMethod(pjp.getSignature().getName()); // 操作方法
//获取方法调用时传递的参数
Object[] args = pjp.getArgs();
op.setParamAndValue(Arrays.toString(args));
long start_time = System.currentTimeMillis();
//放行
Object object = null;
try {
object = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}

long end_time = System.currentTimeMillis();
System.out.println(operateLog.value() + (end_time - start_time));
op.setCostTime(end_time - start_time);
if(object != null){
op.setReturnClass(object.getClass().getName());
op.setReturnValue(object.toString());
}else{
op.setReturnClass("java.lang.Object");
op.setParamAndValue("void");
}
log.error("error");
//operationLogService.saveOrUpdate(op);// 插入日志
System.out.println(" ************************** 记录日志 [end] *************************** ");
return object;
}
}

其中需要注意点语法

execution(修饰符 返回类型 切入点类 切入点方法(参数) 异常抛出)

修饰符: 可选,支持通配符,(public/private/protected)

返回类型: 必填,支持通配符,可以使用 * 来匹配所有的返回值类型

切入点类: 可选,支持通配符,指定切入点类

切入点方法: 必填,支持通配符,指定要匹配的方法名,可以使用"*"通配符来匹配所有方法

参数: 若无可不填,指定方法声明中的形参列表,支持两个通配符,即*和…

其中*代表一个任意类型的参数,而…代表零个或多个任意类型的参数

() 匹配一个不接受任何参数的方法

(…) 匹配一个接受任意数量参数的方法,可以是零个或多个

(*) 匹配一个接受一个任何类型的参数的方法,只能是一个

(*,String) 匹配一个接受两个参数的方法,其中第一个参数是任意类型,第二个参数必须是String类型

异常抛出: 可选,支持通配符,指定方法声明抛出的异常

这是具体的例子

<!-- 【1、拦截所有public方法】 -->
<aop:pointcut expression="execution(public * *(..))" id="pt"/>

<!-- 【2、拦截所有save开头的方法】 -->
<aop:pointcut expression="execution(* save*(..))" id="pt"/>

<!-- 【3、拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->
<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/>

<!-- 【4、拦截指定类的所有方法】 -->
<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.*(..))" id="pt"/>

<!-- 【5、拦截指定包,以及其自包下所有类的所有方法】 -->
<aop:pointcut expression="execution(* com..*.*(..))" id="pt"/>

<!-- 【6、多条件】 -->
<!-- 或:|| or -->
<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) || execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />

<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) or execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />

<!-- 且:&& and --> <!-- 语法虽然没错,但,没意义 -->
<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) && execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />

<aop:pointcut expression="execution(* com.shore.dao.impl.UserDao.save(..)) and execution(* com.shore.dao.impl.MessageDao.save(..))" id="pt" />

<!-- 【7、取非值:not ! 不拦截指定的规则,拦截除此之外的所有类的方法】 -->
<aop:pointcut expression="!execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/> <!-- 注意not前必须有空格 -->

<aop:pointcut expression=" not execution(* com.shore.dao.impl.UserDao.save(..))" id="pt"/>

下面是使用中遇到的坑

由于我是在serviceImpl中使用自定义注解,导致无法找到代理对象,导致注解失效,这里引用某位网友的例子。  https://blog.csdn.net/c493337577/article/details/104348119

版权声明:本文为CSDN博主「c493337577」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/c493337577/article/details/104348119

我的解决方法原理上和他的类似,但是我用他的方法提示service未初始化

我是通过   ((IPolicyService)AopContext.currentProxy()).run(dummy);
获取代理对象调用被注解的方法,解决了注解失效问题

自定义注解中的 object = pjp.proceed();

这句话是代替你执行被注解的方法,如果你在注解方法内还有@component可能会重复执行

关于自定义注解统计方法执行时,存在注解了的方法调用其他方法,那么统计时间问题

@OperateLog("run-controller")
@GetMapping("/run")
@ApiOperation(value = "run")
public void run() {
syso();
System.out.println("1111111");
}


void syso(){
try {
Thread.sleep(1000);
syso1();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("被执行了");
}

void syso1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("被执行了");
}

************************ 记录日志 [start] ******************************
被执行了
被执行了
1111111
run-controller2022
[13:50:48.926] [NOT_SET] [http-nio-8080-exec-1] [d4fa6554-d720-4bc7-9fbb-8e2c01fcbc98] [ERROR] c.b.s.m.b.i.c.a.OperateAdvice:67 error
************************** 记录日志 [end] ***************************

总结,通过日志可以看出,注解统计的俩个方法的总共时间

举报

相关推荐

0 条评论