面向切面编程,可以将业务代码和功能代码分开,比如日志打印和权限控制等等,避免重复代码和解耦
。通过动态代理,运行期修改字节码信息,实现字节码增强
,根据原有类生成代理类。
切入点 pointcount
在哪个方法,哪个类
切入
通知 advice
切入的内容
切面 aspect
切入点+通知
advior 另一种切面
切入点+通知,advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
weaving 织入
将切面加入到对象中,创建出代理对象
aspactJ框架的注解
spring对配置aspectJ的注解的类进行处理,为所有切入点织入功能代码。
spring的aop基于动态代理,那么spring源码时怎么根据原对象生成代理对象,放到spring容器中的?这个就涉及到BeanPostProcessor
接口,通过实现这个接口,在bean创建后,会遍历所有实现了这个接口的类,进行bean的加工。而spring提供的aop注解的实现同样如此,通过AbstractAutoProxyCreator
类实现了BeanPostProcessor
。
AbstractAutoProxyCreator类
该类通过获取bean容器中所有实现了Advisor
接口的类,放到ProxyFactory
类中进行生成代理类,对符合的切入点进行增加增强代码。获取所有实现了Advisor的类,相当于一次返回一个得到了各种增强
的代理类。如果不通过这种方式,而是每个都是去实现BeanPostProcessor更改生成的bean,为该bean生成代理类,那么就需要多次生成代理类,显然是不合理的。
多个代理类的代理顺序
根据实现了order接口决定。spring的事物注解的order值是int最大值,优先级最低
通过@Order(1)注解或者实现order类,指定执行顺序,数字越小越优先执行。
源码:ReflectiveAspectJAdvisorFactory
spring 提供 @Transactional 注解提供给开发者方便的开启事务和提交事务。
使用位置
可用与类上和方法上,可用于接口上、实现类上。用于类上即相当于给类中的所有方法都加上事务处理。被修饰的方法需要是public
的,否则不会生效。
使用方式
注入DataSourceTransactionManager类,配置事务管理器的数据源,事务管理器将通过这个数据源获取连接。
spring项目可以通过xml中配置tx:annotation-driven
开启事务,soringboot可以通过@EnableTransactionManagement注解开启事务。
原理
事务的处理也是通过aop的形式,声明了BeanFactoryTransactionAttributeSourceAdvisor
类,实现了Advisor
接口。切入点
通过类上和方法上的注解,匹配是否包含Transactional注解,符合的话则取出注解上的属性,为当前的bean创建代理对象。符合后
最终的事务处理源码在TransactionInterceptor::invoke
。
默认隔离级别
处理隔离级别的源码
在AbstractPlatformTransactionManager::getTransaction
方法。
逻辑在源码DataSourceTransactionManager::doGetTransaction
中。
通过TransactionSynchronizationManager
类,用ThreadLocal
存储一个map
,map的key是数据源datasource
对象,也就是创建事务管理器时赋值的对象。map的value为ConnectionHolder
对象,该对象包含数据库连接Connection
和当前事务状态transactionActive
。
也就是说,spring将连接等事务相关信息放到threadlocal
类,当调用另一个事务方法时,另一个事务方法会从threadlocal取出当前事务信息。
什么时候取threadlocal中的事务信息?什么时候把连接放到ConnectionHolder中?什么时候把ConnectionHolder放到TransactionSynchronizationManager中?
在AbstractPlatformTransactionManager::getTransaction
方法中,一开始先通过doGetTransaction
获取threadlocal
中的事务信息,获取后进行事务隔离级别判断(比如如果级别是mandaytory
,则如果缓存中没有事务信息就报错)。之后会调用doBegin
方法,事务信息不存在的话会通过datasource
获取连接,将连接封装到ConnectionHolder
类,关闭事务自动提交,如果设置了readOnly则会执行SET TRANSACTION READ ONLY
,还有设置事务超时时间等。最后将ConnectionHolder
放到threadlocal
中。
简单的说就是会先去ThreadLocal取出事务信息,开始事务时会把事务信息放到threadlocal中
通过实现Ordered
类,重写getOrder方法返回排序值实现。