当前位置:主页 > 查看内容

非Spring管理Bean如何添加AOP呢?

发布时间:2021-09-09 00:00| 位朋友查看

简介:前几天有个朋友问了一个问题,觉得可以给大家分享一下。 问题如下图 归其根本这是个历史项目,里面有很多的类并没有交给spring管理,但现在需要统一添加日志。 面对这样的问题,其实只要了解AOP的原理,就会有多种方法。AOP都是基于动态代理来实现,而动态代……

前几天有个朋友问了一个问题,觉得可以给大家分享一下。

问题如下图

归其根本这是个历史项目,里面有很多的类并没有交给spring管理,但现在需要统一添加日志。

面对这样的问题,其实只要了解AOP的原理,就会有多种方法。AOP都是基于动态代理来实现,而动态代理常见的就是cglib和java动态代理,不了解的可以看下之前干货君写的文章

  • java动态代理为什么需要基于接口
  • cglib动态代理对类没有任何限制吗?

但此两种方法似乎在这样的场景不好实现,需要修改大量的代码,那么有没有什么好的方案呢?

答案当然是有。

首先要清楚的是AOP的底层实现原理就是字节码,我们只需要从字节码层面,就一定可以解决这样的问题。因此可以利用编译期增强和运行期增强,常见的方案有两种,一种Java Agent技术,另一种 AspectJ方案。

Java Agent

Java Agent中文名字叫做java 探针,可以在运行java时指定探针程序,对原程序无侵入,常见的一些APM工具都会这样,如skywalking,后续有机会给大家介绍下。如下图


java agent的主要原理就是利用JVMTI(JVM Tool Interface),JVM用来暴露一些供用户扩展的接口集合,因此可以在此处做一些运行期字节码增强。

Java Agent内容比较多,有很多大家熟悉的工具都是基于它去做的,例如阿里的arthas。本文就不介绍了,后期会给大家详细介绍下Java Agent。

AspectJ方案

可以利用aspectj + javac来编译织入代码,也可以利用maven插件aspectj-maven-plugin,下面利用AspectJ注解 + aspectj-maven-plugin来实战一下。

aspectj-maven-plugin官网 http://www.mojohaus.org/aspectj-maven-plugin/usage.html

引入依赖

编译增强,依赖此jar

  1. import org.aspectj.lang.annotation.Aspect; 
  2.  
  3. import org.aspectj.lang.annotation.Before; 
  4.  
  5. import org.aspectj.lang.annotation.Pointcut; 
  6.  
  7. @Aspect 
  8.  
  9. public class Aop { 
  10.  
  11.  
  12.  
  13. @Pointcut("execution(* com.ganhuojun.gracefulshutdown.controller..*.*(..))"
  14.  
  15. public void pointcut1(){ 
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22. @Before("pointcut1()"
  23.  
  24. public void before(){ 
  25.  
  26. System.out.println("controller before"); 
  27.  
  28.  

定义注解

注意:该注解不要交给spring管理

  1. <plugin> 
  2.  
  3. <groupId>org.codehaus.mojo</groupId> 
  4.  
  5. <artifactId>aspectj-maven-plugin</artifactId> 
  6.  
  7. <version>1.11</version> 
  8.  
  9. <configuration> 
  10.  
  11. <complianceLevel>1.8</complianceLevel> 
  12.  
  13. <source>1.8</source> 
  14.  
  15. <!--<showWeaveInfo>true</showWeaveInfo>--> 
  16.  
  17. <!--<Xlint>ignore</Xlint>--> 
  18.  
  19. <encoding>UTF-8</encoding> 
  20.  
  21. <sources> 
  22.  
  23. <source> 
  24.  
  25. <basedir>src/main/java</basedir> 
  26.  
  27. <!--此处使用include一致会导致织入失败,暂时未找到好的解决办法,不写则引用所有的Aspect--> 
  28.  
  29. <!--<includes>--> 
  30.  
  31. <!--<include>**/Aop.java</include>--> 
  32.  
  33. <!--<include>**/ControllerAop.aj</include>--> 
  34.  
  35. <!--</includes>--> 
  36.  
  37. <excludes> 
  38.  
  39. <exclude>**/ServiceAop.java</exclude> 
  40.  
  41. </excludes> 
  42.  
  43. </source> 
  44.  
  45. </sources> 
  46.  
  47. </configuration> 
  48.  
  49. <executions> 
  50.  
  51. <execution> 
  52.  
  53. <goals> 
  54.  
  55. <goal>compile</goal> 
  56.  
  57. </goals> 
  58.  
  59. </execution> 
  60.  
  61. </executions> 
  62.  
  63. </plugin> 

 配置maven插件

  1. <plugin> 
  2.  
  3. <groupId>org.codehaus.mojo</groupId> 
  4.  
  5. <artifactId>aspectj-maven-plugin</artifactId> 
  6.  
  7. <version>1.11</version> 
  8.  
  9. <configuration> 
  10.  
  11. <complianceLevel>1.8</complianceLevel> 
  12.  
  13. <source>1.8</source> 
  14.  
  15. <!--<showWeaveInfo>true</showWeaveInfo>--> 
  16.  
  17. <!--<Xlint>ignore</Xlint>--> 
  18.  
  19. <encoding>UTF-8</encoding> 
  20.  
  21. <sources> 
  22.  
  23. <source> 
  24.  
  25. <basedir>src/main/java</basedir> 
  26.  
  27. <!--此处使用include一致会导致织入失败,暂时未找到好的解决办法,不写则引用所有的Aspect--> 
  28.  
  29. <!--<includes>--> 
  30.  
  31. <!--<include>**/Aop.java</include>--> 
  32.  
  33. <!--<include>**/ControllerAop.aj</include>--> 
  34.  
  35. <!--</includes>--> 
  36.  
  37. <excludes> 
  38.  
  39. <exclude>**/ServiceAop.java</exclude> 
  40.  
  41. </excludes> 
  42.  
  43. </source> 
  44.  
  45. </sources> 
  46.  
  47. </configuration> 
  48.  
  49. <executions> 
  50.  
  51. <execution> 
  52.  
  53. <goals> 
  54.  
  55. <goal>compile</goal> 
  56.  
  57. </goals> 
  58.  
  59. </execution> 
  60.  
  61. </executions> 
  62.  
  63. </plugin> 

 排除spring的aop

如果对spring aop比较熟悉的都知道,spring的aop也是基于AspectJ的,因此需要exclude的,已经配置到mavn的地方了。

编译&运行&测试

编译后class文件已经被织入了相关代码,如下图


运行相关日志输出如下

说明功能已经实现。


本文转载自网络,原文链接:https://www.toutiao.com/i6904437426844893704/
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐