目录
五.声明式事务
一.SpringAop的概念
Aop(Aspect Oriented Programming)是一种面向切面的编程思想,是面向对象(OOP)编程的一种补充和完善。它通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一的添加额外的功能的一种技术。
面向对象编程:纵向继承机制
面向切面编程:横向抽取机制
Aop的基本原理为:把非核心业务代码抽取出来封装到切面类中进行管理,通过切入点定位连接点的位置将抽取出来的非核心业务代码作用到目标方法中。
二.SpringAop的相关术语
1.横切关注点:从目标对象中抽取出来的非核心业务代码。同一个项目中,我们可以使用多个横切关注电脑对相关方法进行多个不同方面的增强。这个概念不是天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能就有十个横切关注点。
2.通知:每一个横切关注点上要做的事情都需要通过写一个方法来实现,把横切关注点封装到当前的切面类中,切面类中每一个横切关注点为一个通知方法。
通知方法分为五种:
①前置通知:在被代理的目标方法执行前执行
②返回通知:在被代理的目标方法成功执行完后执行
③异常通知:在被代理的目标方法出现异常后执行
④后置通知:在被代理的目标方法最终结束后执行
⑤环绕通知:使用try...catch....finally结构绕整个被代理的目标方法,包括上面四种通知对应 的所有位置。
3.切面:封装通知方法的类
4.目标:目标对象就是要进行功能增强的对象
5.代理:为目标对象创建的一个代理对象,在AOP中不需要我们创建生成代理对象,因为它封装 的就是代理模式。
6.连接点:抽取横切关注点的位置,这也是一个逻辑概念,不是语法定义的,把方法排成一排, 每一个横切位置成轴方法,把方法从上到下执行的顺序看成y轴,x轴和y轴的交叉点就是连接 点。
7.切入点:表达式(从代码层面表示连接点的位置),切入点就是定位连接点的方式。每个类中 都包含多个连接点,所以连接点是客观存在的事物,如果把连接点看作数据库中的记录,那么 切入点就是查询记录的SQL语句。Spring的AOP技术可以通过切入点定位到特定的连接点。切 点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条 件。
8.织入(Weaving):
Apply the aspect to the target to generate the proxy.
把切面应用到目标对象来创建代理对象的过程,织入一般发生在如下几个时机:
- 编译时: 当一个类文件被编译时织入,需要特殊的编译器才能实现,比如AspectJ的编译器
- 类加载时: 当使用特殊的类加载器在目标被加载到虚拟机之前增强类的字节代码
- 运行时: 切面在运行的某个时刻被织入,SpringAOP就是以此种方式织入的,原理是是用了JDK的动态代理技术。
三.AOP的作用
AOP的基本流程:从目标对象中把非核心业务代码抽取出来,这个非核心业务代码就是横切关注点,把横切关注点封装到一个类中,这个类就是切面类,切面中每一个横切关注点就是一个通知方法,抽取横切关注点的位置就是连接点,从代码层面定位到横切关注点的位置就用切入点。
作用:
1.简化代码:把方法中固定位置的重复代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。
2.代码增强:把特定的功能封装到切面类中,哪里有需要就用在哪里,被套用了切面逻辑的方法就被切面给增强了。
四.动态代理
1.JDK动态代理:要求必须有接口,最终生成的代理类和目标类实现相同的接口。
在com.sun.proxy包下,类名为$proxy2
2.Cglib动态代理:最终生成的代理类会继承目标类,并且和目标类在相同的包下。
Spring基于注解的AOP,对AOP思想的实现时候AspectJ注解层,具体实现为动态代理
动态代理特点:字节码随用随创建,随用随加载
动态代理作用:不修改源码的基础上对方法增强
需要在配置文件中开启基于注解的AOP:
注意事项:切面类和目标类都需要交给IOC容器进行管理,切面类必须通过@Aspect注解标识为一个切面。
切面的优先级:在切面上添加@Order注解,默认值为Integer的最大值,数字越小,优先级越高。
五.声明式事务
1.编程式事务:事务功能的相关操作全部通过自己编写代码实现。
编程式事务的实现方式存在缺陷:
- 细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。
- 代码复用性不高:如果没有抽取出来,每次实现功能都需要自己编写代码,代码没有得到复用。
2.声明式事务
既然事务控制的代码有规律可循,代码结构的基本时候确定的,所以框架可以将固定模式的代码抽取出来,进行相关的封装。
封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。
好处:
提高了开发效率
清除了冗余代码
框架会总和考虑相关领域在实际开发环境下有可能遇到的各种问题,进行了健壮性,性能等个方面的优化。
3.基于注解的声明式事务
1.添加相关依赖
2.使用Jdbc配置数据源dataSource
3.在配置文件中定义事务管理DataSourceTransactionManager
4.使用@Transactional注解标识方法或类用事务进行管理
注意:@Transactional注解加在哪个方法上,哪个方法就是连接点
加在类上,类中所有方法都是连接点。
4.声明式事务属性
①只读:设置为只读,只有查询操作,就能够告诉数据库这个操作不涉及写操作。
使用readonly=true设置,如果当前事务有增删改时,设置只读会报错,报SQLExxception错误。
②超时:事务在执行过程中,有可能遇到问题导致程序卡住,从而长时间占用数据库资源,可以通过超时属性设置一个超时时间,在规定的时间中,如果当前事务没有执行,就会强制回滚并抛出异常。
timeout default=-1:表示一直等,等程序执行完或者报错为止。
例如:设置超时时间为3秒,超出设置的超时时间后,没有执行完,就抛出TransactionTimeOutException异常。
③回滚:有四种,前两个是因为什么而回滚,第一个写异常的对象对应的class对象,第二个写类的全类名,后两种是不因为什么而回滚,同上面一样。
事务属性: 传播行为
传播行为是指业务方法平行调用时,决定被调用方法的事务应该如何处理的问题,默认使用REQUIRED。
PROPAGATION_REQUIRED: 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS: 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY :使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW :新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED :以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER :以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED :如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。