八、通勤路上搞定 Spring 面试(3)

漫谈面试系列
面试题回顾:

  1. 如果要你实现 Spring IOC,你会注意哪些问题?
  2. BeanFactory 和 FactoryBean 有什么区别,Bean 是怎么加载出来的?
  3. AOP是什么,怎么实现,Spring 事务和它有什么关系?

前言

在之前的文章中,我们对 IOC 容器的基本功能以及产生 bean 的基本流程有了一定的了解,那么 Spring AOP 与这两者有什么关系,接下来让我们了揭开 Spring AOP 的面具。

3、AOP是什么,怎么实现,Spring 事务和它有什么关系?

在面向对象的世界中,某些对象之间不存在直接关系(继承或组合),但是他们却需要拥有部分相似的行为,例如日志的打印,这个时候,我们就得在这些类里面都写上日志打印的代码,才能完成业务需求,但是这种改法导致的问题便是维护的复杂度增加,这个问题,正是面向对象的问题,面向对象无法针对行为进行统一维护,而 AOP 的出现便是用于解决这个问题。
AOP 译为面向切向编程,切面可以理解为行为的管理中心,我们可以将 AOP 解释为把某种行为进行封装,然后"织入"到需要这种行为的类中的一种机制。
而我们实现 AOP 需要做三件事,分别是:

  1. 封装统一的行为:Spring AOP 通过 Advice 描述封装的行为以及这个行为的执行时机
  2. 找到需要"织入"的位置:Spring AOP 里面通过 Pointcut 描述需要织入的位置;现在我们有了行为 Advice 以及位置 Pointcut 后,那么就需要一个类将这两者整合,方便灵活组合调用,而整合这两者的类,叫做 Advisor (通知器) 或 Aspect(切面)。其中 Advisor 只包含一个 Pointcut 和一个 Advice,而 Aspect 可以包含多个 Pointcut 和多个 Advice。
  3. 将行为"织入"到需要的类当中:Spring AOP 通过动态代理来实现行为"织入",动态代理的方式有 JDK 动态代理和 CGLIB 动态代理两种。

一般我们使用 Spring AOP 的时候(以下内容都是基于注解式编程),需要我们自定义一些业务方面的 Aspect,然后使用 @EnableAspectJAutoProxy注解开启了 AOP 功能,这样我们便可以在执行特定的方法时触发自己编写的 Advice 了。目前如果我们使用 springboot 并且引入 spring-boot-starter-aop 的依赖后,会默认开启 AOP 功能。那么,Spring 是什么时候帮我们将 Aspect 里面的 Advice 织入到相应的 bean 当中呢?

既然 @EnableAspectJAutoProxy是开启 AOP 的注解,那么它肯定有相关的方法来帮我们将 Spring AOP 的功能加入到 Spring 当中,我们进入 @EnableAspectJAutoProxy注解,会发现其导入了一个 AspectJAutoProxyRegistrar 类,进入这个类,最终我们会发现这个类往 Spring IOC容器中注入了一个AnnotationAwareAspectJAutoProxyCreator 类,而这个类实现了 BeanPostProcessor 接口,从第二节 bean 的加载中我们得知,BeanPostProcessor 会在 bean 初始化好后进行增强处理,而 Spring AOP 正是通过这个 BeanPostProcessor 来给 IOC 容器返回一个被织入了 Advice 的代理类。

下面我们简单讲一下 AnnotationAwareAspectJAutoProxyCreator 这个类是如何运作 AOP 功能:

  1. bean 初始化完后执行 BeanPostProcessor 的 postProcessAfterInitialization() 方法,这里进入 AbstractAutoProxyCreator 的 postProcessAfterInitialization() 方法,其中 AbstractAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator的父类
  2. 获取所有的 Advisor ,其中AnnotationAwareAspectJAutoProxyCreator负责的任务是将带有 @Aspect 的 bean 通过反射的方式,将里面的 Advice 和 Pointcut 进行一一匹配然后转换为一个个的 Advisor 进行返回;也就是说,最终 Spring AOP 只有 Advisor ,而没有 Aspect 。其实 Aspect 只是方便我们进行代码统一编写的工具注解而已。
  3. 通过 AopUtils工具类,从所有的 Advisor 中筛选出可以织入当前 bean 的 Advisor ,例如通过路径、方法名等方式进行匹配
  4. 如果当前 bean 有符合条件的 Advisor ,则通过 proxyFactory工厂类生产对应的代理类,如果 proxy-target-class 设置为 true ,则无脑使用 CGLIB ,否则针对有接口的类使用 JDK 动态代理生成代理对象。

这里有关具体的动态代理生成过程就不详说了,有兴趣的读者可以参考其他博客


讨论完 Spring AOP 后,我们再来看看 Spring 的事物和 AOP 的关系。
Spring的事务是对数据库事务的封装,本质的实现还是在数据库,假如数据库不支持事务的话,Spring的事务是没有作用的。也就是说,我们使用Spring 事务,本质上是Spring在我们执行自己的代码前后调用了数据库的事务接口。

看到这里,我们不免猜得出来,Spring 事务是通过 AOP 往我们的相关类的方法中织入了底层事务接口的调用,这样便可以解释,为什么我们在同一个类中通过 this 调用添加了事物注解的方法不会生效,因为我们只有调用了由 AOP 生成的代理类,才会触发有关事务的开启、提交、回滚等代码,而通过 this 来调用本类的方法,是不会运行有关事务的代码。

总的来说,Spring 事务基于 Spring AOP 来实现,而 Spring AOP 是通过 Spring 的后置器 BeanPostProcessor 来实现。

最后

Spring AOP 的内容虽然不多,但还是希望读者可以在阅读文章的同时浏览相关源码进行辅助,可以有效提高对这篇文章的理解,下面我们回到这个问题:

  AOP是什么,怎么实现,Spring 事务和它有什么关系?

如果你们可以很流畅的回答这个问题,那么恭喜你,该章节的内容已经全部掌握,如果不行,希望可以回到对应问题讲解的地方,或者对某个不了解的点进行额外的知识搜索,尽量用自己组织的语言回答这些问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值