著论准过秦,作赋拟子虚。这篇文章主要讲述#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理相关的知识,希望能为你提供帮助。
@TOC
前言通过前面对源码的分析,我们基本了解了整个 AOP 代理生产的过程:
- 找到与 bean 匹配的所有的 Advisor
- 使用所有匹配的 Advisor 来为 bean 生成生成动态代理
- 通过动态代理类执行 Advice
- 将 Spring AOP 与 Spring IoC 进行结合
版本约定Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)
正文前面分析 如何为 Pointcut 匹配的类生成动态代理类 时,我们发现,Spring 是在 bean 创建时的第三步 initializeBean 时,调用
AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization()
来产生代理 bean 的。说的更具体点,是在调用父类的
AbstractAutoProxyCreator#wrapIfNecessary()
方法时,获取到与 bean 匹配的 Advisor,通过 ProxyFactory 来创建的代理类。public Object postProcessAfterInitialization(@Nullable Object bean, String beanName)
if (bean != null)
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean)
return wrapIfNecessary(bean, beanName, cacheKey);
return bean;
// AbstractAutoProxyCreator#wrapIfNecessary()
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
......// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY)
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理 bean
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
接下来,我们就通过
AnnotationAwareAspectJAutoProxyCreator
这条线索,来分析一下含有 @Transactional 的类是如何产生 AOP 代理类的?准备一个干净极简的工程首先,我们先准备一下干净极简的工程, 创建一个 CarService,含有一个 @Transactional 方法,让这个最简单的工程 run 起来。
@Service
public class CarService
@Autowired
private CarMapper carMapper;
@Transactional
public void insertWithTx(Car car)
carMapper.insert(car);
throw new RuntimeException("出错啦");
@SpringBootApplication
@MapperScan("com.kvn.tx.mapper")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class TxApplication public static void main(String[] args)
SpringApplication.run(TxApplication.class, args);
通过源码处的条件断点来研究我们直接在
AbstractAutoProxyCreator#wrapIfNecessary()
方法中创建代理处打一个断点。可以发现,匹配到的 Advisor 是:
BeanFactoryTransactionAttributeSourceAdvisor
。我们再看一下
BeanFactoryTransactionAttributeSourceAdvisor
被引用的地方,可以发现是在 ProxyTransactionManagementConfiguration
中。而 ProxyTransactionManagementConfiguration 被引用的地方则是
@EnableTransactionManagement
ProxyTransactionManagementConfiguration
具体的配置类如下:@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor)
// 使用的 pointcut 是: TransactionAttributeSourcePointcut
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// TransactionAttributeSource 是用来获取事务元数据的
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 针对 @Transactional 使用的 Advice
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null)
advisor.setOrder(this.enableTx.<
Integer>
getNumber("order"));
return advisor;
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource()
return new AnnotationTransactionAttributeSource();
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(
TransactionAttributeSource transactionAttributeSource)
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null)
// 设置事务管理器
interceptor.setTransactionManager(this.txManager);
return interceptor;
通过 ProxyTransactionManagementConfiguration 的配置,我们可以看出,它定义了 advisor : BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisorAdvisor 是 Spring AOP 产生代理类的关键配置,它包含了 pointcut 和 advice。(通常是 PointcutAdvisor)
pointcut 用于匹配 bean,对应的 advice 用于通知。
BeanFactoryTransactionAttributeSourceAdvisor 中包含的 pointcut 和 advice:
- pointcut :
TransactionAttributeSourcePointcut 用于匹配 @Transactional 标记的方法对应的类(或者直接被 @Transactional 标记的类) - advice:
TransactionInterceptor 用于处理事务方法的执行拦截
TransactionInterceptor#invoke()
来进行拦截处理的。// TransactionInterceptor#invoke()
public Object invoke(MethodInvocation invocation) throws Throwable
// Work out the target class: may be @code null.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<
?>
targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupports invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
文章图片
可以看出,invokeWithinTransaction() 是带事务执行目标方法,如果目标方法正常返回的话,就会提交事务;如果目标方法抛出异常,则会判断该异常是否需要回滚事务。
invokeWithinTransaction()
的处理流程如下:- 获取待执行方法上的事务属性 TransactionAttribute
即:方法上的 @Transactional 注解中的配置属性 - 选取事务管理器
TransactionManager
- 通过
TransactionManager
开启事务 - 执行目标方法
- 正常返回,则通过
TransactionManager
提交事务
异常返回,则判断是否需要回滚事务
具体是定义了一个 Advisor : BeanFactoryTransactionAttributeSourceAdvisor,来拦截 @Transactional 方法。
BeanFactoryTransactionAttributeSourceAdvisor 中包含的 pointcut 和 advice:
- pointcut :
TransactionAttributeSourcePointcut 用于匹配 @Transactional 标记的方法对应的类(或者直接被 @Transactional 标记的类) - advice:
TransactionInterceptor 用于处理事务方法的执行拦截
invokeWithinTransaction()
方法来完成事务方法的执行。invokeWithinTransaction()
的处理流程如下:- 获取待执行方法上的事务属性 TransactionAttribute
即:方法上的 @Transactional 注解中的配置属性 - 选取事务管理器
TransactionManager
- 通过
TransactionManager
开启事务 - 执行目标方法
- 正常返回,则通过
TransactionManager
提交事务
异常返回,则判断是否需要回滚事务(默认对 RuntimeException 和 Error 进行回滚)
【#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理】有关 Spring 源码方面的问题欢迎一起交流,备注:51cto (vx: Kevin-Wang001)
博主好课推荐:
课程 | 地址 |
---|---|
Dubbo源码解读——通向高手之路 | https://edu.51cto.com/course/23382.html |
正则表达式基础与提升 | https://edu.51cto.com/course/16391.html |
推荐阅读
- HDFS源码解析(教你用HDFS客户端写数据)
- HGDB中any用法
- #yyds干货盘点#RabbitMQ的简单模式案例讲解,非常详细
- #私藏项目实操分享# Angular @HostListener装饰器的使用笔记
- 使用Nginx搭建图片服务器#yyds干货盘点#
- 原生JavaScript灵魂拷问,你能答上多少#yyds干货盘点#
- 7招!实现安全高效的流水线管理
- K8SIngress
- Intune中win32应用部署---Intune终结点管理(10)