黑马就业班——Spring框架:part3 -- spring中的aop和基于XML以及注解的AOP配置(包含ThreadLocal、动态代理分析)

本文详细介绍了Spring框架中的AOP概念和ThreadLocal机制。通过分析案例,展示了如何利用动态代理解决事务控制问题。讨论了Spring中基于XML和注解的AOP配置,以及在实际项目中的应用。最后布置了使用AOP技术完成转账操作的作业。
  • 本文参考文档:《Spring5第三天.pdf》
  • 本文代码项目:spring_day03_account、 spring_day03_proxy(路径:G:\idea_java_project\)
  • 本文大部分内容参考上面项目的代码!!!

今日内容

1、完善我们的account案例,并分析案例中问题
	
2. 回顾之前讲过的一个技术:动态代理,介绍动态代理另一种实现方式

3. 解决案例中的问题
	1) spring的一些新注解使用

4. AOP的概念、spring中的AOP相关术语、spring中基于XML和注解的AOP配置

1、完善我们的account案例,并分析案例中问题
  分析之前的 spring_day02_account_xmlioc 项目。我们创建一个新的项目 spring_day03_account 来进行分析,主要看这个项目的代码解析。

ThreadLocal

  什么是ThreadLocal:顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。
  这里其实可以把ThreadLocal看作一个容器,我们创建ThreadLocal的时候,会使用泛型定义ThreadLocal中存储的数据的类型,如 ThreadLocal ,创建一个只存储Connection类型数据的ThreadLocal。然后当一个线程第一次访问 ThreadLocal 的时候,会给这个线程创建一个Connection对象,并以键值对的方式放入ThreadLocal中,键是当前的线程,值是这个线程对应的Connection对象。这个线程后面访问ThreadLocal的时候,就不会再创建新的Connection,而是直接从ThreadLocal中获取Connection。如果其他线程访问ThreadLocal,就会为其他线程创建Connection对象并放入ThreadLocal中。
  也就是说,对于每一个访问ThreadLocal的线程,在ThreadLocal中都 有且仅有一个Connection,且不同线程的Connection直接互不干扰

  有关ThreadLocal类的应用,可以参考文章:添加链接描述 、 视频:添加链接描述
  有关多线程与并发的知识,参考 黑马张孝祥的多线程视频。


  对案例中的一个疑问:为什么前面一条数据库操作语句会从数据库连接池获取一个Connection的解析,参考文章:添加链接描述

在这里插入图片描述
  通过项目 spring_day03_account ,我们发现之前发生的问题解决了,但是也出现了新的问题。

1、bean.xml配置变成十分麻烦,多了很多类以及依赖注入,程序变得乱七八糟;
2、由于类之间有许多方法之间的调用,方法之间的调用过多,导致方法之间的依赖变得很大。(类之间的依赖是在一个类中创建另一个类的对象;方法之间的依赖,是在一个方法中调用另一个方法)——我们应该尽量保持方法之间的独立,而不是使得方法之间有紧密的依赖关系。

  现在的问题是,如何使得 AccountServiceImpl 类的 transfer 方法既可以不需要调用 TransactionManager 控制事务的方法,从而降低方法之间的依赖,又可以使得 transfer 方法按照 TransactionManager 中事务控制的流程执行。


2、动态代理的分析
  动态代理的解析,这部分参考 spring_day03_proxy 项目以及视频7、8的分析。
  参考自己的文章:《黑马就业班(02.JavaWeb+项目实战\day11_Filter&Listener):代理模式解析》
  视频8以及之前,我们使用的是基于接口的动态代理,如果被代理的对象不实现任何接口,那么代理是无法实现的。
  我们下面使用基于子类的动态代理来实现。使用子类的动态代理,项目需要导入 cglib 的jar包坐标。具体参考视频9以及项目 spring_day03_proxy 的cglib部分。
  通过对动态代理的分析,我们发现动态代理可以对我们现有的方法进行增强,提供我们需要的功能,并且不需要修改我们当前方法的代码。


3、使用动态代理解决上面案例中的问题
  我们使用动态代理实现事务的控制。对于项目 spring_day03_account ,我们想通过AccountServiceImpl来实现,而不是通过 AccountServiceImpl_OLD 来实现,前者较为简单,但是它没有提供控制事务方法的 TransactionManager类的对象!
  为了便于区分,我们创建一个与 spring_day03_account 项目相同的项目 spring_day03_account_solve 来解决这个问题,参考视频10以及项目 spring_day03_account_solve 的factory包下的代码。
  使用动态代理之后,我们发现之前AccountServiceImpl中控制事务的重复的代码都消失了,不需要在AccountServiceImpl操作数据库的方法中调用TransactionManager中控制事务的方法,解除了方法之间的依赖。但是,bean.xml中的配置仍然十分繁琐!
  下面我们要想办法解决配置较为繁琐的问题,就使用Spring的AOP解决。


4、AOP
4.1 AOP的概念
  AOP: 全称是 Aspect Oriented Programming 即: 面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。根据上面的分析,其实增强就是在代理对象的invoke中,把重复的代码加进去。

作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码、提高开发效率、维护方便
AOP实现:使用动态代理实现

  更多AOP配置,参考视频11以及文档的介绍。

4.2 spring中的AOP的相关术语和细节
  我们学习 spring 的AOP,就是通过配置的方式(XML配置或注解配置),实现上面案例的功能。
  AOP的相关术语,见文档——2.1.2 AOP 相关术语以及视频12解析。(关键是视频的解析)

Joinpoint(连接点):
	所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
	我们之前案例中业务层接口AccountService的方法都是连接点。AccountService的方法是连接业务以及增强方法的点。我们想把增强的代码,也就是TransactionManager中控制事务的代码加到业务中来,必须通过业务层接口AccountService的方法,从而使得我们的业务方法形成完整的业务逻辑。
	(业务层接口中所有的方法都是连接点,包括有被增强的方法以及没有被增强的方法)

Pointcut(切入点):
	所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
	(业务层接口中被增强的方法才是切入点,没有被增强的方法是连接点但不是切入点)
	
Advice(通知/增强):
	所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
	通知的类型: 前置通知,后置通知,异常通知,最终通知,环绕通知。
	(基于接口的动态代理中,invoke方法可以拦截被代理对象被执行的方法。invoke中拦截到之后,就要对被代理对象AccountServiceImpl的方法提供事务的支持,那么提供事务支持的TransactionManager就是通知。关于通知的类型,见下面的图)
	
Introduction(引介):
	引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方
法或 Field。(现阶段没有使用到)

Target(目标对象):
	代理的目标对象。(AccountServiceImpl就是被代理的对象,里面的方法需要进行增强。在BeanFactory中,其实可以把AccountService看作被代理的目标对象,它是AccountServiceImpl的接口,最后增强的其实是同样的方法)
	
Weaving(织入):
	是指把增强应用到目标对象来创建新的代理对象的过程。
	spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
	(我们在堆AccountServiceImpl中方法进行增强并创建代理对象的过程,就是织入)
	
Proxy(代理) :
	一个类被 AOP 织入增强后,就产生一个结果代理类。(代理AccountServiceImpl的对象)

Aspect(切面):
	是切入点和通知(引介)的结合。	
	建立切入点方法和通知方法在执行调用过程中的对应关系,就是切面。
	比如我们上面的案例,TransactionManager的方法就是通知方法,而AccountService中需要增强的方法就是切入方法,我们之前是使用编码的方式,可以控制这2类方法的执行顺序。比如通知中开启事务在切入方法执行之前,通知中提交事务在切入方法执行之后,这样可以很容易控制他们的顺序。
	AOP中怎么使用配置的方式,把这两类方法的执行顺序或者说是执行关系说清楚,这里面的配置方式,就是所说的切面。
	配置内容:说明白哪个service需要增强、哪些增强的方法需要使用、这些方法何时执行。这些整个配置过程,就是所谓的切面。(见视频12-11.20 的解析,有点抽象,注意理解)

通知/增强 的类型

  AOP的相应细节如下:

1、在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
	基于接口的动态代理要求被代理类至少实现一个接口,而基于子类的动态代理要求被代理类不能是final类型。当然,如果一个类既实现了接口,又不是final类,它2种动态代理都可以使用。在spring中,可以手动控制使用的代理方式。

  学习 spring 中的 AOP 要明确的事。(视频12-13.20解析)

a、开发阶段(我们做的)
	编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
	把公用代码抽取出来,制作成通知。(开发阶段最后再做): AOP 编程人员来做。
	在配置文件中,声明切入点与通知间的关系,即切面。: AOP 编程人员来做。
b、运行阶段( Spring 框架完成的)
	Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对
象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行

4.3 spring中基于XML的AOP配置
  切面的配置方式:参考项目 spring_day03_springAOP 以及视频13- 的解析。
  案例中AOP基于XML的配置流程如下:
在这里插入图片描述
  4种常用的通知类型:参考项目 spring_day03_adviceType 。

4.4 spring中基于注解的AOP配置
  参考视频19,项目 spring_day03_annoAOP 代码。需要注意的是,基于注解的AOP在bean.xml方法中,xml的约束与基于XML的AOP不同,需要进行修改(按源码修改即可)。

作业

  使用AOP技术,完成上面的Account表的转账操作——参考项目:spring_day03_account_homework。注意要bean.xml的配置要使用AOP的配置。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值