本篇分享的内容是在相同类中方法间调用时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)没起作用,我们有如下常用两种方式处理方案;

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

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

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

 @EnableAspectJAutoProxy(exposeProxy = true)

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

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

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

最新文章

  1. Linux超快速安装Ruby on Rails
  2. PHP-PHP-FPM的max_children一些误区
  3. xml对象的序列化和反序列化
  4. php碎片
  5. 视频1-14待JSP课程看完再练习
  6. 第一课 Hello
  7. JS原生回到顶部效果
  8. .net常見面試題(四)
  9. innerHTML和innerText
  10. ASP.NET状缓存Cache的应用-提高数据库读取速度
  11. js 数字
  12. C语言负数的除法和求余运算
  13. jq模拟操作
  14. zabbix web监控模板
  15. jmeter如何进行MQTT性能测试(测试前期准备一,性能测试需求)
  16. CMD运行JAVA出现编码GBK的不可映射字符处理方法?
  17. Python编程快速上手-让繁琐工作自动化-第二章习题及其答案
  18. h5新增标签及css3新增属性
  19. [转]免费数学神器!再复杂的公式,只要有照片就能转成LaTeX
  20. LCT摘要

热门文章

  1. BootStrap实现简单响应式导航菜单
  2. [Short-Circuit Constraint Violation]警告解决办法
  3. 解决oh-my-zsh中git分支显示乱码问题
  4. JSmooth 将java代码打包成exe
  5. H5中的history方法Api介绍
  6. 洛谷 P2016 战略游戏
  7. UI 组件 | Button
  8. 由group by引发的sql_mode的学习
  9. 从 Python 之父的对话聊起,关于知识产权、知识共享与文章翻译
  10. Oracle数据库之SQLPLUS