相同类中方法间调用时日志Aop失效处理

本篇分享的内容是在相同类中方法间调用时Aop失效处理方案,该问题我看有很多文章描述了,不过大多是从事务角度分享的,本篇打算从日志aop方面分享(当然都是aop,失效和处理方案都是一样),以下都是基于springboot演示;

  • 快速定义个日志Appender
  • 快速定义个拦截器和日志注解(aop)
  • 模拟相同类中方法间调用时aop失效
  • Aop失效处理方案(就两种足够了)

快速定义个日志Appender

日志我还是喜欢log4j,大部分朋友也同样吧,这里lombok与log4j结合来完成我们的日志,如下maven包(最新mvn还是建议去官网找):

 1         <dependency>
 2             <groupId>org.projectlombok</groupId>
 3             <artifactId>lombok</artifactId>
 4         </dependency>
 6         <dependency>
 7             <groupId>org.slf4j</groupId>
 8             <artifactId>slf4j-api</artifactId>
 9             <version>2.0.0-alpha0</version>
10         </dependency>
11         <dependency>
12             <groupId>org.slf4j</groupId>
13             <artifactId>slf4j-log4j12</artifactId>
14             <version>2.0.0-alpha0</version>
15         </dependency>

先继承log4j的AppenderSkeleton重写下append方法,简单记录下就行,如下:

 1 public class MyLogAppend extends AppenderSkeleton {
 2     private String author;
 3
 4     public void setAuthor(String author) {
 5         this.author = author;
 6     }
 7
 8     @Override
 9     protected void append(LoggingEvent loggingEvent) {
10         System.out.println(
11                 JsonUtil.formatMsg("date -- {},level -- {},message -- {}",
12                         LocalDate.now(),
13                         loggingEvent.getLevel(),
14                         loggingEvent.getMessage()));
15     }
16
17     @Override
18     public void activateOptions() {
19         super.activateOptions();
20         System.out.println("author:" + this.author);
21     }
22
23     @Override
24     public void close() {
25         this.closed = true;
26     }
27
28     @Override
29     public boolean requiresLayout() {
30         return false;
31     }
32 }

然后项目根目录增加log4j.properties配置文件,配置内容定义info级别,就此完成了log4j自定义记录日志了:

1 log4j.rootLogger=info,MyLogAppend
2 log4j.appender.MyLogAppend=com.sm.component.log.MyLogAppend
3 log4j.appender.MyLogAppend.author=shenniu003

快速定义个拦截器和日志注解(aop)

通常同类中不同方法调用是常事,可以直接用this.xx();有时有这样需求,需要各个调用方法时候的参数记录下来,因此我们需要个拦截器,再增加个自定义注解方便使用:

 1 @Aspect
 2 @Component
 3 @Slf4j
 4 public class MyLogInterceptor {
 5
 6     private final String pointcut = "@annotation(com.sm.component.ServiceLog)";
 7
 8     @Pointcut(pointcut)
 9     public void log() {
10     }
11
12     @Before(value = "log()")
13     void before(JoinPoint joinPoint) {
14         Signature signature = joinPoint.getSignature();
15         log.info(
16                 JsonUtil.formatMsg("method:{},params:{}",
17                         signature.toLongString(),
18                         joinPoint.getArgs()));
19     }
20 }
1 @Documented
2 @Target({ElementType.METHOD})
3 @Retention(RetentionPolicy.RUNTIME)
4 public @interface ServiceLog {
5 }

拦截器拦截带有@ServiceLog注解的方法,然后记录请求参数和方法名;

模拟相同类中方法间调用时aop失效

利用上面完成的日志注解,这里在OrderService类中用getOrderDetail方法去调用getOrderLog方法,他两都标记日志注解便于记录参数日志;同时getOrderDetail方法也调用另外一个UserService类中的getNickName方法,便于比较:

 1 @Service
 2 public class OrderService {
 3
 4     @Autowired
 5     UserService userService;
 6
 7     @ServiceLog
 8     public String getOrderDetail(String orderNum) {
 9         String des = "订单号【" + orderNum + "】月饼一盒";
11         userService.getNickName(orderNum);
13         this.getOrderLog(orderNum + "11111");
15         return des;
16     }
17
18     @ServiceLog
19     public List<String> getOrderLog(String orderNum) {
20         List<String> logs = new ArrayList<>();
21         IntStream.range(0, 5).forEach(b -> {
22             logs.add("用户" + b + "购买成功");
23         });
24         return logs;
25     }
26 }
1 @Service
2 public class UserService {
3     @ServiceLog
4     public String getNickName(String userId) {
5         return "神牛" + userId;
6     }
7 }

方法调用重点截图:

然后运行程序,接口触发调用getOrderDetail方法,以下拦截器中记录的日志信息:

能够看出拦截器只记录到了getOrderDetail和getNickName方法的日志,因此可以肯定getOrderLog根本没有走拦截器,尽管在方法上加了日志@ServiceLog注解也没用。

Aop失效处理方案(就两种足够了)

就上面相同类中方法间调用拦截器(aop)没起作用,我们有如下常用两种方式处理方案;

  1. 用@Autowired或Resource引入自身依赖
  2. 开启暴露代理类,AopContext.currentProxy()方式获取代理类

第一种:主要使用注解方法引入自身代理依赖,不要使用构造的方式会有循环依赖问题,以下使用方式:

第二种:通过暴露代理类方式,实际原理是把代理类添加到当前请求的ThreadLocal里面,然后在使用时从ThreadLocal中获取代理类,再调用对应的方法,开启方式需要:

1 @EnableAspectJAutoProxy(exposeProxy = true)

然后方法中如下使用即可:

最后来看下使用这两种方式正常走拦截器效果:

不管是日志拦截器或事务,他们都是aop的方式,底层原理走的代理方式,只有使用代理类才会正常执行拦截器,而this.xxx()使用的是自身实例对象,因此会出现上面失效的情况。

原文地址:https://www.cnblogs.com/wangrudong003/p/11508107.html

时间: 2024-08-29 05:52:42

相同类中方法间调用时日志Aop失效处理的相关文章

关于一个类中方法的调用

大家都知道:对象是对客观事物的抽象,类是对对象的抽象,对象是类的实例. 在类中来调用方法.不过调用方法也有种种的情况.(如下几种情况) 情况一:同一个类中的两个方法相互调用 1.如果两个方法都是普通的方法,也就是非静态的方法的话,是可以直接调用的.例 ( public void a(){ system.out.println(“内容”): b(): } public void b(){ system.out.println(“内容2”): } ) 2.如果两个方法都是静态的方法,那么也是可以直接

关于类中方法的调用

同一个类中的两个方法相互调用: 1.两种方法都是普通的方法:可以直接用方法名调用 2.两种方法都是静态方法:可以直接用方法名调用 3.一种方法为静态,一种方法为普通: ①在静态方法中调用普通方法:不可以直接使用,需要创建对象 ②在普通方法中调用静态方法:可以直接用方法名调用

jupyter 中文件间调用

1.在需要文件间调用的文件夹下创建Ipynb_importer.py文件,文件内容为 import io, os,sys,types from IPython import get_ipython from nbformat import read from IPython.core.interactiveshell import InteractiveShell class NotebookFinder(object): """Module finder that loca

equals方法被调用时字符串和对象的顺序

之前改的bug,一开始我先判断sortKey不为空,然后再去判断sortKey的值,见下图, 代码push后,同事审核后,叫我将sortKey和值得顺序调换一下,说这样就不用再判断为空.这是改之后的代码,见下图, 问了几个人,说是避免空指针异常,我说我前面已经对sortKey做了一个不为空判定,有人回答说虽然没有错,但是多判断了一次,而且从代码规范上看显得多余. 问题来了,equals方法被调用时,谁在前谁在后,这里面有什么讲究?经过查阅相关资料,整理了一些知识点. equals方法在Objec

android开发中关于继承activity类中方法的调用

android开发中关于继承activity类中的函数,不能在其他类中调用其方法. MainActivity.java package com.example.testmain; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState)

找到 相同类中 某一个 的索引

在点击li 的时候,找到当前li 在所有li 中的索引  使用$(this)  作为index() 的参数 原文地址:https://www.cnblogs.com/yigexiaojiangshi/p/9164889.html

C# 方法的调用

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 临时 8 { 9 class Person 10 { 11 public class Class1 12 { 13 public static void Method() 14 { 15 Console.WriteLin

相同类、不同类调用变量、常量及方法

<?phpnamespace app\admin\controller;use think\Controller; class Test extends controller{ const name='PHP软件开发工程师'; private $a='1'; public function index($kgs) { $b=$kgs*2; return $b; } public function test(){ echo self::name; //相同类中调用常量 echo $this->a

java中方法调用

JAVA中方法的调用[基础] 一.调用本类中的方法 方法一.被调用方法声明为static ,可以在其他方法中直接调用.示例代码如下: public class HelloWord { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String str="HelloWord!"; int a=0; int b=a+1; int result=