本文例子完整源码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AOP%E9%AB%98%E7%BA%A7%E2%80%94%E2%80%94%E6%BA%90%E7%A0%81%E5%AE%9E%E7%8E%B0%EF%BC%882%EF%BC%89Spring%20AOP%E4%B8%AD%E9%80%9A%E7%9F%A5%E5%99%A8%EF%BC%88Advisor%EF%BC%89%E4%B8%8E%E5%88%87%E9%9D%A2%EF%BC%88Aspect%EF%BC%89

  之所以还未正式进入Spring AOP的源码,是因为我在阅读Spring AOP生成代理对象时遇到了一点小麻烦让我不得不暂时停止,转而理清有关Spring AOP中的两个概念性问题。

  前面的博客里都没有提到过“通知器”这个概念,在《Spring实战》书中也只是简单地说明了在xml中<aop:advisor>用于定义一个通知器,此后便没再说明,而是使用<aop:aspect>定义一个切面。而在《Spring技术内幕》中有关Spring AOP章节中则是介绍了AOP中三个概念:通知、切点、通知器。在这时,我对“通知器”产生了很大的疑惑,查阅了相关资料并没有满意的答案,于是决定自己一探究竟。

  首先来讨论定义通知器相关的使用方法。 定义一个通知类,其中包含前置通知和后置通知,注意如果是使用<aop:advisor>定义通知器的方式实现AOP则需要通知类实现Advice接口,前置通知方法对应的是MethodBeforeAdvice,后置通知方法对应的是AfterReturningAdvice。

 1 package com.demo;
 2
 3 import org.springframework.aop.AfterReturningAdvice;
 4 import org.springframework.aop.MethodBeforeAdvice;
 5 import org.springframework.stereotype.Component;
 6
 7 import java.lang.reflect.Method;
 8
 9 /**
10  * Created by Kevin on 2017/11/15.
11  */
12 @Component("advisorTest")
13 public class AdvisorTest implements MethodBeforeAdvice, AfterReturningAdvice{
14
15     /**
16      * 前置通知
17      * @param method
18      * @param args
19      * @param target
20      * @throws Throwable
21      */
22     @Override
23     public void before(Method method, Object[] args, Object target) throws Throwable {
24         System.out.println("前置通知");
25     }
26
27     /**
28      * 后置通知
29      * @param returnValue
30      * @param method
31      * @param args
32      * @param target
33      * @throws Throwable
34      */
35     @Override
36     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
37         System.out.println("后置通知");
38     }
39 }

  定义一个需要被代理的目标对象。

 1 package com.demo;
 2
 3 import org.springframework.stereotype.Component;
 4
 5 /**
 6  * 目标对象,需要被代理的类及方法
 7  * Created by Kevin on 2017/11/15.
 8  */
 9 @Component("testPoint")
10 public class TestPoint {
11
12     public void test() {
13         System.out.println("方法调用");
14     }
15 }

  我们要达到的目的就是在test方法调用前和调用后分别打印“前置通知”和“后置通知”。

  applicationContext.xml中定义通知器如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 7
 8     <context:component-scan base-package="com.demo"/>
 9
10     <aop:config>
11         <aop:pointcut id="test" expression="execution(* com.demo.TestPoint.test())"/>
12         <aop:advisor advice-ref="advisorTest" pointcut-ref="test"/>
13     </aop:config>
14
15 </beans>

  最后的运行结果符合预期。那么问题来了,如果我们只想在定义的这个切点 <aop:pointcut id="test" expression="execution(* com.demo.TestPoint.test())"/>里只配置前置通知,这个时候怎么办呢?答案是,通过以上方式是不可以的。也就是说如果通过定义Advisor的方式,在有的地方比较局限,狭隘来讲通过定义Advisor通知器的方式,只能定义只有一个通知和一个切入点的切面。当然一个通知不准确,因为上面可以看到只要实现不同的通知接口即可代理,但如果实现了多个通知接口,而只想使用一个时就不可以了。通知器是一个特殊的切面。

  接着来讨论定义切面相关的使用方法。 如果使用<aop:aspect>定义切面的方式,通知类是可以不用实现任何通知接口的,这是很大一个便利。同样要实现上面例子的功能,定义一个通知类,包括前置通知和后置通知。

 1 package com.demo;
 2
 3 import org.springframework.stereotype.Component;
 4
 5 /**
 6  * Created by Kevin on 2017/11/15.
 7  */
 8 @Component("aspectTest")
 9 public class AspectTest {
10
11     /**
12      * 前置通知
13      */
14     public void doBefore() {
15         System.out.println("前置通知");
16     }
17
18     /**
19      * 后置通知
20      */
21     public void doAfter() {
22         System.out.println("后置通知");
23     }
24 }

  目标对象和上面的例子一致,紧接着是applicationContext.xml中切面的配置。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 7
 8     <context:component-scan base-package="com.demo"/>
 9
10     <aop:config>
11         <aop:aspect ref="aspectTest">
12             <aop:pointcut id="test" expression="execution(* com.demo.TestPoint.test())"/>
13             <aop:before method="doBefore" pointcut-ref="test"/>
14             <aop:after-returning method="doAfter" pointcut-ref="test"/>
15         </aop:aspect>
16     </aop:config>
17 </beans>

  可以看到我们通过<aop:aspect>定义了一个切面,如果只需要前置通知,则只定义<aop:before>就可以了,这和<aop:advisor>是很大的不同,由此可知通过<aop:aspect>定义切面的方式可以在其中灵活地定义通知,而不必像通知器那样约束。

  实际上可以这么说,通知器是一个特殊的切面。而在最开始那两篇博客中没有提到是因为那两个例子中使用的是AspectJ注解,而在AspectJ注解中并没有与此对应的概念。

  在实际中用到的<aop:advisor>场景最多的莫过于在Spring中配置事务。除此之外,很少用到,也不建议使用。因为最大的一个问题就是定义通知时需要实现通知接口,这违背了一点Spring“非侵入式”编程的初衷。

  这篇博客穿插在源码的其中是为了更好的理清Spring AOP中各种概念问题,缘由我在开头已经说过,接下来就正式开始Spring AOP源码的解读。

这是一个能给程序员加buff的公众号 

转载于:https://www.cnblogs.com/yulinfeng/p/7841167.html

Spring AOP高级——源码实现(2)Spring AOP中通知器(Advisor)与切面(Aspect)相关推荐

  1. Spring Core Container 源码分析七:注册 Bean Definitions

    前言 原本以为,Spring 通过解析 bean 的配置,生成并注册 bean defintions 的过程不太复杂,比较简单,不用单独开辟一篇博文来讲述:但是当在分析前面两个章节有关 @Autowi ...

  2. 框架源码专题:Spring是如何集成Mybatis的?Spring怎么管理Mapper接口的动态代理

    文章目录 1. Spring集成Mybatis代码示例 2. Spring 如何解析Mybatis配置文件 3. Spring是怎么管理Mapper接口的动态代理的 4. Spring整合Mybati ...

  3. 专治不会看源码的毛病--spring源码解析AOP篇(2017版)

    昨天有个大牛说我啰嗦,眼光比较细碎,看不到重点.太他爷爷的有道理了!要说看人品,还是女孩子强一些.原来记得看到一个男孩子的抱怨,说怎么两人刚刚开始在一起,女孩子在心里就已经和他过完了一辈子.哥哥们,不 ...

  4. spring aop 注入源码解析

    spring aop 注入源码解析 aop启动 AbstractApplicationContext.java @Overridepublic void refresh() throws BeansE ...

  5. spring aop 注入源码解析 1

    spring aop 注入源码解析 aop启动 AbstractApplicationContext.java @Overridepublic void refresh() throws BeansE ...

  6. 框架源码专题:Spring的Aop实现原理,Spring AOP 与 AspectJ 的关系

    文章目录 1. Spring AOP 与 AspectJ 的关系 2. JDK和Cglib动态代理的区别 3. Spring AOP应用案例 4. Spring AOP有几种配置方式? 5. Spri ...

  7. 【Spring 源码阅读】Spring IoC、AOP 原理小总结

    Spring IoC.AOP 原理小总结 前言 版本约定 正文 Spring BeanFactory 容器初始化过程 IoC 的过程 bean 完整的创建流程如下 AOP 的过程 Annotation ...

  8. spring源码深度解析---创建AOP代理之获取增强器

    spring源码深度解析-创建AOP代理之获取增强器 在上一篇的博文中我们讲解了通过自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这 ...

  9. spring 多线程 事务 源码解析(一)

    大家好,我是烤鸭: 今天分享的是spring 多线程事务源码分析. 环境: spring-jdbc 5.0.4.REALEASE 今天分享一下spring事务的方法,这一篇还没涉及到多线程. 简单说一 ...

  10. 一箭双雕 刷完阿里P8架构师spring学习笔记+源码剖析,涨薪8K

    关于Spring的叙述: 我之前死磕spring的时候,刷各种资料看的我是一头雾水的,后面从阿里的P8架构师那里拿到这两份资料,从源码到案例详细的讲述了spring的各个细节,是我学Spring的启蒙 ...

最新文章

  1. Java代码优化(长期更新)
  2. jQuery ajax实现
  3. 茌平计算机中考成绩查询,中考成绩查询系统入口2021
  4. Python读写ini文件的封装类
  5. python是什么专业学的-什么样的人适合学Python,应该怎么学?
  6. 基础04继承、super、this、抽象类
  7. sonarqube插件开发(二) 开发插件
  8. windows中配置ant环境变量
  9. IAR软件ZigBee物联网
  10. HBase二级索引实现方案
  11. autoit mysql update_RobotFramework+selenium+requests+autoit+mysql+appium 环境搭建
  12. 元宇宙、区块链和潘家园
  13. 投掷骰子的python代码_模拟骰子(Python),掷骰子
  14. hdfs配置文件(hdfs.site.xml)详解
  15. 销售易CRM怎么样?
  16. 分销小程序功能有哪些?如何使用分销小程序实现裂变卖货?
  17. Servlet知识概括详解
  18. Bad Smell (代码的坏味道)
  19. 服务器系统盘大文件检测指令,服务器系统盘大文件检测指令
  20. python-使用递归函数计算阶乘

热门文章

  1. R Markdown与RStudio IDE深度结合
  2. R语言数据可视化---交互式图表recharts包
  3. eclipse搭建简单的web服务,使用tomcat服务
  4. 使用 WordPress 自定义字段功能为文章添加下载按钮
  5. 初步搭建RocketMQ环境
  6. JSP转译成Servlet详细过程
  7. 软件工程第一次作业程序开发历程
  8. C#:Md5和Sha1两种加密方式
  9. Hosting WCF in SharePoint 2007 (Part 1) 基本部署(转)
  10. access与sqlserver数据转换