aop思想
面向切面编程:是代码复用的一种手段,是面向对象编程的补充。
做了什么事情:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代码、事务控制代码、性能监控代码。
AOP 相关术语
- Target 目标类
- Proxy 代理
- Joinpoint 连接点
- Pointcut 切点
- Advice 增强
- Advisor 切面
- Wearing 织入
- Introduction 引入
增强的类型
- before advice 前置增强
- after advice 后置增强
- around advice 环绕增强
- throws advice 抛出增强
- introduction advice 引入增强
动态代理原理和代码示例待补充
Cglib源码:
- https://blog.csdn.net/woshilijiuyi/article/details/83448407
- https://blog.csdn.net/yu_kang/article/details/88530016
- https://www.cnblogs.com/monkey0307/p/8276810.html
https://blog.csdn.net/a837199685/article/details/68930987
代理方式
有接口默认JDK动态代理,可以指定为CGlib
无接口CGlib
CGlib代理
cglib代理是支持同类方法相互调用时的拦截,但是spring cglib代理方式并不支持。
其具体表现为,同一个类中没有事务注解的方法a调用有事务注解的方法b时,事务注解不生效。
spring aop与AspectJ
spring aop借鉴了AspectJ的注解,特别是AspectJ的切点表达式,简化了原有的spring的配置。
需要注意:spring aop仅仅是借鉴AspectJ的注解,而不是整合了完整的AspectJ。
完整的AspectJ是需要定义AspectJ类(扩展了java的语法),使用特定的前端编译器将.java文件编译为.class文件时,就将代理类生成了,因此说是静态代理。
事务
编程式和声明式事务
- 编程式事务: 在业务代码中添加事务控制代码,这样的事务控制机制就叫做编程式事务
- 声明式事务: 通过xml或者注解配置的⽅式达到事务控制的⽬的,叫做声明式事务
特性
原子性(操作的原子性),一致性(数据的一致性),隔离性(多个数据库连接),持久性
数据并发问题:
- 脏读:⼀个线程中的事务读到了另外⼀个线程中未提交的数据。
- 不可重复读:⼀个线程中的事务读到了另外⼀个线程中已经提交的update的数据。
- 幻读:⼀个线程中的事务读到了另外⼀个线程中已经提交的insert或者delete的数据。
隔离级别
- Read uncommitted 读已提交:无法避免任意一个
- Read committed 读已提交:可以避免脏读
- Repeatable read 可重复读:可以避免脏读和不可重复读
- Serializable 串⾏化:可以全部避免
传播机制
事务是在service层中的方法控制的。方法A调用方法B,如果AB都被添加了事务控制,就需要进⾏事务的⼀些协商。
我们是站在B方法的角度观察:
- PROPAGATION_REQUIRED:默认。如果已存在事务,则使用当前事务。如果没有事务,新建一个事务。
- PROPAGATION_SUPPORTS:如果已存在事务,则使用当前事务。如果没有事务,已非事务方式执行。
- PROPAGATION_MANDATORY:如果已存在事务,则使用当前事务。如果没有事务,抛出异常。
- PROPAGATION_REQUIRES_NEW:新建事务,如果已存在事务,则挂起。
- PROPAGATION_NOT_SUPPORTED:已非事务方式执行,如果已存在事务,则挂起。
- PROPAGATION_NEVER:如果已存在事务,已非事务方式执行,如果已存在事务,则抛出异常。
- PROPAGATION_NESTED:嵌套事务。子事务失败不影响主事务,主事务失败则一起回滚。
只读
超时
超时时间是和数据库交互时重置,最后事务提交时判定是否超时。
回滚规则
默认回滚是运行时异常回滚,受检查异常不回滚
注意
- 如果AOP使用了JDK动态代理,对象内部方法互相调用不会被Spring的AOP拦截,@Transactional注解无效。
- 如果AOP使用了CGLIB代理,事务方法或者类不是public,无法被外部包访问到,或者是final无法继承,@transactional注解无效。