Java-第十五部分-源码解读-事务梳理

115 阅读2分钟

源码解读全文

初始化流程

EnableTransactionManagement注解

  • ProxyTransactionManagementConfiguration注册,其中分别注册了三个Bean
  • 实际名字为"org.springframework.transaction.config.internalTransactionAdvisor";,作为切面类,包括transactionAttributeSourcetransactionInterceptor

封装了事务的切点以及相关属性 image.png

  • transactionAttributeSource切点属性资源 image.png
  • transactionInterceptor切面方法执行器 image.png
  • 由此可以看出,事务是直接将切面方法注册进容器,并没有通过AOP扫描所有Bean,获取切面资源

重要的类

  • PlatformTransactionManager,模板接口,规定了commit/rollback/getTransaction方法

生成代理对象流程

  • 初始化Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
  • 调用初始化后的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  • 调用AbstractAutoProxyCreatorpostProcessAfterInitialization,其中调用wrapIfNecessary(bean, beanName, cacheKey);
  • 获取可以运用到该类上的切面执行器Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

此时specificInterceptorsinternalTransactionAdvisor切面类

  • 创建代理对象Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

将信息封装给proxyFactory,根据是否实现接口cglib/jdk创建代理

getAdvicesAndAdvisorsForBean获取该类的切面执行器

  • 找到所有切面List<Advisor> candidateAdvisors = findCandidateAdvisors();

获取所有cachedAdvisorBeanNames,通过getBean添加到advisors

  • 根据该类进行筛选List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  1. 筛选AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
  2. 遍历所有切面
  3. 如果是PointcutAdvisor的类型,调用canApply(pca.getPointcut(), targetClass, hasIntroductions); image.png

PointcutAdvisor.canApply切面匹配

  • 获取该类及其接口的实现类classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
  • methodMatcher.matches(method, targetClass)
  1. 获取所有事务切点属性资源TransactionAttributeSource tas = getTransactionAttributeSource();
  2. 尝试获取当前方法的事务信息,如果没有,为其创建TransactionAttribute txAttr = findTransactionAttribute(specificMethod);,解析@Transactional注解
  • 当比较到internalTransactionAdvisormethodMatcher实际上为TransactionAttributeSourcePointcut,是事务的类
  • 通过事务中的transactionAttributeSource,进行解析@Transactional注解,并进行缓存

调用流程

  • 从切面中获取执行链

1.将该方法的切面转换为执行器MethodInterceptor[] interceptors = registry.getInterceptors(advisor); 2. 通过获取切面类的增强器Advice advice = advisor.getAdvice();,并转换成执行器interceptors.add((MethodInterceptor) advice); 3. 保存在this.methodCache.put(cacheKey, cached); 4. 此时获得的是transactionInterceptor

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

image.png

  • 封装成CglibMethodInvocation方法执行器,链式调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
  • 调用TransactionInterceptor.invoke image.png

invokeWithinTransaction

  • 创建事务信息TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  • 执行目标方法retVal = invocation.proceedWithInvocation();,此时回到执行链执行流程,此时执行链已完成,执行目标方法,执行完成后,执行提交/回滚 image.png

createTransactionIfNecessary

  • 开始事务startTransaction(def, transaction, debugEnabled, suspendedResources);
  • 正式开始DataSourceTransactionManagerdoBegin(transaction, definition);
  • 检查是否有数据库连接txObject.hasConnectionHolder(),没有则创建
  1. 创建连接Connection newCon = obtainDataSource().getConnection();
  2. 设置给ConnectionHoldertxObject.setConnectionHolder(new ConnectionHolder(newCon), true);
  • 设置事务为falsecon.setAutoCommit(false);
  • 如果txObject.isNewConnectionHolder(),将这个连接绑定给线程TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
  • 将当前数据源的连接,绑定给线程,ThreadLocal image.png

数据库执行过程

  • 获取链接ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

resourceimage.png

  • 执行过程中,需要获取连接jdbcTemplate.execute("update bank set money = money + 100 where name = 'zhangsan';"); image.png
  • 传入的是一个接口匿名实现类,doInStatement的实现,sql为语句 image.png