相同类中方法间调用时日志Aop失效处理
本篇分享的内容是在相同类中方法间调用时Aop失效处理方案,该问题我看有很多文章描述了,不过大多是从事务角度分享的,本篇打算从日志aop方面分享(当然都是aop,失效和处理方案都是一样),以下都是基于springboot演示;
- 快速定义个日志Appender
- 快速定义个拦截器和日志注解(aop)
- 模拟相同类中方法间调用时aop失效
- Aop失效处理方案(就两种足够了)
快速定义个日志Appender
日志我还是喜欢log4j,大部分朋友也同样吧,这里lombok与log4j结合来完成我们的日志,如下maven包(最新mvn还是建议去官网找):
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.-alpha0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.-alpha0</version>
</dependency>
先继承log4j的AppenderSkeleton重写下append方法,简单记录下就行,如下:
public class MyLogAppend extends AppenderSkeleton {
private String author; public void setAuthor(String author) {
this.author = author;
} @Override
protected void append(LoggingEvent loggingEvent) {
System.out.println(
JsonUtil.formatMsg("date -- {},level -- {},message -- {}",
LocalDate.now(),
loggingEvent.getLevel(),
loggingEvent.getMessage()));
} @Override
public void activateOptions() {
super.activateOptions();
System.out.println("author:" + this.author);
} @Override
public void close() {
this.closed = true;
} @Override
public boolean requiresLayout() {
return false;
}
}
然后项目根目录增加log4j.properties配置文件,配置内容定义info级别,就此完成了log4j自定义记录日志了:
log4j.rootLogger=info,MyLogAppend
log4j.appender.MyLogAppend=com.sm.component.log.MyLogAppend
log4j.appender.MyLogAppend.author=shenniu003
快速定义个拦截器和日志注解(aop)
通常同类中不同方法调用是常事,可以直接用this.xx();有时有这样需求,需要各个调用方法时候的参数记录下来,因此我们需要个拦截器,再增加个自定义注解方便使用:
@Aspect
@Component
@Slf4j
public class MyLogInterceptor { private final String pointcut = "@annotation(com.sm.component.ServiceLog)"; @Pointcut(pointcut)
public void log() {
} @Before(value = "log()")
void before(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
log.info(
JsonUtil.formatMsg("method:{},params:{}",
signature.toLongString(),
joinPoint.getArgs()));
}
}
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceLog {
}
拦截器拦截带有@ServiceLog注解的方法,然后记录请求参数和方法名;
模拟相同类中方法间调用时aop失效
利用上面完成的日志注解,这里在OrderService类中用getOrderDetail方法去调用getOrderLog方法,他两都标记日志注解便于记录参数日志;同时getOrderDetail方法也调用另外一个UserService类中的getNickName方法,便于比较:
@Service
public class OrderService { @Autowired
UserService userService; @ServiceLog
public String getOrderDetail(String orderNum) {
String des = "订单号【" + orderNum + "】月饼一盒";
userService.getNickName(orderNum);
this.getOrderLog(orderNum + "");
return des;
} @ServiceLog
public List<String> getOrderLog(String orderNum) {
List<String> logs = new ArrayList<>();
IntStream.range(, ).forEach(b -> {
logs.add("用户" + b + "购买成功");
});
return logs;
}
}
@Service
public class UserService {
@ServiceLog
public String getNickName(String userId) {
return "神牛" + userId;
}
}
方法调用重点截图:
然后运行程序,接口触发调用getOrderDetail方法,以下拦截器中记录的日志信息:
能够看出拦截器只记录到了getOrderDetail和getNickName方法的日志,因此可以肯定getOrderLog根本没有走拦截器,尽管在方法上加了日志@ServiceLog注解也没用。
Aop失效处理方案(就两种足够了)
就上面相同类中方法间调用拦截器(aop)没起作用,我们有如下常用两种方式处理方案;
- 用@Autowired或Resource引入自身依赖
- 开启暴露代理类,AopContext.currentProxy()方式获取代理类
第一种:主要使用注解方法引入自身代理依赖,不要使用构造的方式会有循环依赖问题,以下使用方式:
第二种:通过暴露代理类方式,实际原理是把代理类添加到当前请求的ThreadLocal里面,然后在使用时从ThreadLocal中获取代理类,再调用对应的方法,开启方式需要:
@EnableAspectJAutoProxy(exposeProxy = true)
然后方法中如下使用即可:
最后来看下使用这两种方式正常走拦截器效果:
不管是日志拦截器或事务,他们都是aop的方式,底层原理走的代理方式,只有使用代理类才会正常执行拦截器,而this.xxx()使用的是自身实例对象,因此会出现上面失效的情况。
相同类中方法间调用时日志Aop失效处理的更多相关文章
- C#中方法的调用
C#中方法的调用 1.同一个类中方法的调用: 静态方法可以直接调用静态方法 静态方法不能直接调用非静态方法,静态方法先生成. 非静态方法可以直接调用静态方法 如果静态方法要调用非静态的方法,必须使用实 ...
- Spring service本类中方法互相调用事物失效问题
简介 Spring事物利用的是AOP,动态代理采用CGLIB代理(默认,也可以用Proxy代理,但是Proxy代理效率低于CGLIB代理).故只要弄懂Spring的AOP实现,就知道为什么servic ...
- JAVA中方法的调用主要有以下几种
JAVA中方法的调用主要有以下几种: 1.非静态方法 非静态方法就是没有 static 修饰的方法,对于非静态方法的调用,是通过对 象来调用的,表现形式如下. 对象名.方法() eg: public ...
- java中方法传入参数时:值传递还是址传递?
JAVA中的数据类型有两大类型: ① 基本数据类型:逻辑型(boolean).文本型(char).整数型(byte.short.int.long).浮点型(float.double) ② 引用数据类型 ...
- python__基础 : 多继承中方法的调用顺序 __mro__方法
在多继承中,如果一个子类继承了两个平级的父类,而这两个父类有两个相同名字的方法,那么一般先继承谁,调用方法就调用先继承的那个父类的方法.如: class A: def test(self): prin ...
- @Transactional-同一个类中方法自调,调用方法事物失效
问题分析 一个类中的方法调用另一个事物传播性为创建事物的方法,调用的方法事物失效? SpringAOP 代理的Service对象调用了其方法,这个方法再去调用这个Service中的其他方法是没有使用A ...
- 1.7Oob同类中不同方法间的互相调用
import java.util.Scanner; public class Bill { public static final double RATE=150.0; 这里没有创建getter和se ...
- android开发中关于继承activity类中方法的调用
android开发中关于继承activity类中的函数,不能在其他类中调用其方法. MainActivity.java package com.example.testmain; import and ...
- testNG中方法的调用顺序
今天在执行selnium的test case时,总是遇到空指针错误.但是以前也有run成功过,然后换了各种方法定位元素,都失败了,所以怀疑应该不是元素定位不到的问题,所以可能是method之间有依赖, ...
随机推荐
- Java Grammer:数据类型
Java的数据类型 我们知道,Java是一种强类型语言,类型对于Java语言来说非常的重要不言而喻,在Java中,分为基础数据类型和引用数据类型,其中基础数据类型分为了四类八种: 下面,我们来分别说一 ...
- koa2基于stream(流)进行文件上传和下载
阅读目录 一:上传文件(包括单个文件或多个文件上传) 二:下载文件 回到顶部 一:上传文件(包括单个文件或多个文件上传) 在之前一篇文章,我们了解到nodejs中的流的概念,也了解到了使用流的优点,具 ...
- 如何让传统ASP.NET网站在Docker中运行
本文主要描述如何让传统ASP.NET网站在Docker中运行,侧重Docker image 搭建. 使用条件: Docker for windows 用户切换到Windows 容器模式 Windows ...
- python basemap readshapefile二三事
今天要用到basemap读取shp文件报错,查了很多资料,都没有解决. 先是: fig,ax = plt.subplots(figsize=(15,10)) from mpl_toolkits.bas ...
- resolv.conf文件配置相关的案例
引言 操作系统中/etc/resolv.conf配置文件中的内容一般为空,如果该文件配置不正确,将导致ssh.route.netstat命令响应慢的问题. 在/etc/resolv.conf添加错误地 ...
- Java虚拟机(二)-对象创建
这一篇大致说明一下,对象在Java堆中对象分配.内存布局以及访问定位 1.对象的创建 虚拟机在遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引 ...
- 建立第一个G2图表
Step1:引进G2脚本 方法一:引入在线脚本 <script src="https://gw.alipayobjects.com/os/lib/antv/g2/3.4.10/dist ...
- tensorflow学习笔记——图像数据处理
喜欢摄影的盆友都知道图像的亮度,对比度等属性对图像的影响是非常大的,相同物体在不同亮度,对比度下差别非常大.然而在很多图像识别问题中,这些因素都不应该影响最后的结果.所以本文将学习如何对图像数据进行预 ...
- PL/SQL 调用JAVA使用UDP发送数据
步骤如下 1.直接在SQL命令中写入JAVA代码(用SYS帐号执行,不然权限等太麻烦) create or replace and resolve java source named udp as i ...
- java并发系列 - 第28天:实战篇,微服务日志的伤痛,一并帮你解决掉
这是java高并发系列第28篇文章. 环境:jdk1.8. 本文内容 日志有什么用? 日志存在的痛点? 构建日志系统 日志有什么用? 系统出现故障的时候,可以通过日志信息快速定位问题,修复bug,恢复 ...