Spring入门之AOP实践:@Aspect + @Pointcut + @B…
2019-08-29 09:02:14来源:博客园 阅读 ()
Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After
零、准备知识
1)AOP相关概念:Aspect、Advice、Join point、Pointcut、Weaving、Target等。 ref: https://www.cnblogs.com/zhangzongle/p/5944906.html 有代码示例 2)相关注解:@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing一、实践目标
1)@Aspect的功能 2)@Pointcut的切面表达式 3)@Before、@Around、@After、@AfterReturning / @AfterThrowing的时序关系 4)AOP概念的重新梳理和使用二、核心代码
MainController.java包含两个测试函数,分别是doSomething() 和 test()。1 // MainController.java 2 @RestController 3 public class MainController { 4 RequestMapping(value="/doSomething", method = RequestMethod.POST) 5 @CrossOrigin("*") 6 public void doSomething() { 7 System.out.println("This is doSomething"); 8 test(); 9 } 10 11 @RequestMapping(value="/justTest", method = RequestMethod.POST) 12 @CrossOrigin("*") 13 public void test() { System.out.println("This is test");} 14 }
ExampleAop.java为AOP相关代码,定义了pointcut和多个Advice函数。
1 // ExampleAop.java 2 @Component 3 @Aspect 4 @Order(1) 5 public class ExampleAop { 6 7 private static final Logger LOGGER = LoggerFactory.getLogger(ExampleAop.class); 8 9 // 匹配com.example.demo包及其子包下的所有类的所有方法 10 @Pointcut("execution(* com.example.demo..*.*(..))") 11 public void executeService() { 12 } 13 14 @Before("executeService()") 15 public void doBeforeAdvice(JoinPoint joinPoint) throws Exception { 16 LOGGER.info("Before [{}]", joinPoint.getSignature().getName()); 17 } 18 19 @Around("executeService()") 20 public void doAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { 21 LOGGER.info("Around1 [{}]", joinPoint.getSignature().getName()); 22 joinPoint.proceed(); 23 LOGGER.info("Around2 [{}]", joinPoint.getSignature().getName()); 24 } 25 26 @After("executeService()") 27 public void doAfterAdvice(JoinPoint joinPoint) throws Exception { 28 LOGGER.info("After [{}]", joinPoint.getSignature().getName()); 29 } 30 31 @AfterReturning("executeService()") 32 public void doAfterReturningAdvice(JoinPoint joinPoint) throws Exception { 33 LOGGER.info("AfterReturning [{}]", joinPoint.getSignature().getName()); 34 } 35 }
编译并运行jar包,调用接口/doSomething。
1 # 调用接口 2 curl localhost:8080/doSomething
到服务器观察日志。
1 <!-- 后台日志 --> 2 com.example.demo.aop.ExampleAop : Around1 [doSomething] 3 com.example.demo.aop.ExampleAop : Before [doSomething] 4 This is doSomething 5 This is test 6 com.example.demo.aop.ExampleAop : Around2 [doSomething] 7 com.example.demo.aop.ExampleAop : After [doSomething] 8 com.example.demo.aop.ExampleAop : AfterReturning [doSomething]
三、分析与结论
1)@Aspect的功能 在连接点的前后添加处理。在本例中,doSomething() 是连接点,而test() 不是。 是否只有最外层的joinpoint才会被Advice插入?在后面进行简单的探讨和猜测。 2)@Pointcut的切面表达式 ref: https://www.cnblogs.com/liaojie970/p/7883687.html 常用表达式 ref: https://www.jianshu.com/p/fbbdebf200c9 完整表达式 @Pointcut("execution(...)") 是Pointcut表达式,executeService() 是point签名。表达式中可以包含签名的逻辑运算。 常用表达式:1 execution(public * com.example.demo.ExampleClass.*(..)) // ExampleClass的所有公有方法 2 execution(* com.example.demo..*.*(..)) // com.example.demo包及其子包下的所有方法 3 logSender() || logMessage() // 两个签名的表达式的并集
3)@Before、@Around、@After、@AfterReturning / @AfterThrowing的时序关系 @Around1 -> @Before -> 方法 -> @Around2 -> @After -> @AfterReturning / @AfterThrowing(时序问题后面有额外讨论。) 另外可以发现,@Around是可以影响程序本身执行的,如果不调用 joinPoint.proceed(); 就不会执行方法。其他几个都无法影响程序执行。 4)AOP概念的重新梳理和使用 Aspect(切面):使用了@Aspect注解,如ExampleAop类。 Advice(增强):在指定位置进行的增强操作,如方法运行时间统计、用户登录、日志记录等。由@Before、@After等注解标注,如doBeforeAdvice() 方法。 Weaving(织入):AOP就是一种把Advice织入(即嵌入、插入)到Aspect中指定位置执行的机制。 Join point(连接点):Advice执行的位置,也是Advice的参数,是一个具体的方法。如日志中看到的doSomething() 函数。 Pointcut(切点):以表达式的形式表示一组join point,用于由@Pointcut注解定义Advice的作用位置。如@Pointcut("execution(* com.example.demo..*.*(..))") 代表com.example.demo包及其子包下的所有类的所有方法。 Target(对象):被增强的对象,即包含主业务逻辑的类的对象,如ExampleAop类的实例。
四、疑问与讨论
1. 本文说执行顺序为@Around1 -> @Before -> 方法 -> @Around2 -> @After,但有的文章中说是@Before -> @Around1 -> 方法 -> @Around2 -> @After,也有说@Around1 -> @Before -> 方法 -> @After -> @Around2,哪个对? 反正代码跑起来是这个顺序,那就是这个顺序喽。每个Advice都加上sleep拉开时间也没有变化。不知道是否受版本或代码自身影响。 总之可以得到一个结论:@Before / @After 最好不要和@Around混用,执行顺序不好确定。 时序至少总是满足:@Around1 / @Before -> 方法 -> @Around2 / @After -> @AfterReturning / @AfterThrowing 另外找到一篇支持本文执行顺序的文章:https://blog.csdn.net/qq_32331073/article/details/80596084 2. 为何doSomething() 和 test() 都是@Pointcut中选中的作用节点,但只有doSomething() 插入了Advice,而test() 没有呢? 一个猜测:从字面意思理解,@Pointcut对所有代码以表达式为规则剪一刀,一侧是所有的joinpoint,另一侧是普通代码。在joinpoint与另一侧代码间插入一层Advice的代理,另一侧的代码如果要调用joinpoint,则必须经Advice进行增强操作。而不同的joinpoint在同一侧,因此未插入Advice。 有时间再读源码了解其中的机制。(一个猜测)
五、Future Work
1. AOP中还有Advisor等概念,待学习。 2. 切面表达式(@Pointcut里的表达式)规则丰富,待学习。 3. Advice的插入时机,待读源码学习。
原文链接:https://www.cnblogs.com/desertfish/p/11421260.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash