当前位置: 首页 > news >正文

怎么做赌球网站潍坊今日头条新闻最新

怎么做赌球网站,潍坊今日头条新闻最新,长宁网站推广公司,湖北华亚建设工程有限公司网站前言 我们在日常开发的时候经常会用到组合注解,比如:EnableTransactionManagement Transactional、EnableAsync Async、EnableAspectJAutoProxy Aspect。今天我们就来抽丝剥茧,揭开Transactional注解的神秘面纱 EnableTransactionManagement注解的作用 当我们看到类似Ena…

前言

我们在日常开发的时候经常会用到组合注解,比如:@EnableTransactionManagement + @Transactional、@EnableAsync + @Async、@EnableAspectJAutoProxy + @Aspect。今天我们就来抽丝剥茧,揭开@Transactional注解的神秘面纱

@EnableTransactionManagement注解的作用

当我们看到类似@Enablexxx这样的注解,一般源码中都会存在@Import注解。@Import注解在Spring的解析阶段有着十分重要的地位,是Spring的一个重要的扩展点。其注入的class一般继承ImportSelectorImportBeanDefinitionRegistrar接口,作用分别如下

  • 继承ImportSelector接口:selectImports方法返回的类名数组会被解析成bean
  • 继承ImportBeanDefinitionRegistrar接口:会在解析阶段执行registerBeanDefinitions方法

感兴趣的小伙伴可以阅读下方链接对应博文,该博文主要讲解了Spring对@ComponentScan、@Import、@PropertySource、@Bean等注解的解析流程,可以更好的帮助我们理解本篇文章Spring之ConfigurationClassPostProcessor解析流程icon-default.png?t=N7T8https://blog.csdn.net/qq_38257958/article/details/134761961?spm=1001.2014.3001.5501

1.@EnableTransactionManagement注解源码

 

通过上面的源码,我们简单理论分析

@EnableTransactionManagement注解会注入一个类型为TransactionManagementConfigurationSelector的class,该class的父类实现selectImports方法,父类方法又会调用子类的同名方法。根据上文中阐述的@Import注解的作用,此时Spring容器中多了两个BeanDefinition:一个beanClass为AutoProxyRegistrar,另一个beanClass为ProxyTransactionManagementConfiguration

结论1:@EnableTransactionManagement注解会import一个类型为TransactionManagementConfigurationSelector的class,该class实现ImportSelector接口,其接口方法返回[AutoProxyRegistrar,ProxyTransactionManagementConfiguration]类名数组,即Spring容器在后期会存在beanClass为AutoProxyRegistrar和ProxyTransactionManagementConfiguration的两个bean

2.AutoProxyRegistrar源码

AutoProxyRegistrar实现ImportBeanDefinitionRegistrar接口,所以会在Spring的解析阶段执行registerBeanDefinitions方法,我们重点关注截图框住的方法,它会注入一个beanClass为InfrastructureAdvisorAutoProxyCreator的BeanDefinition。InfrastructureAdvisorAutoProxyCreator是BeanPostProcessor(后文简称bpp)的子类,它会在普通bean的生命周期对bean进行一些干预,比如当前bpp就会在Spring执行bpp的postProcessAfterInitialization方法的时候会对bean进行动态代理(这个我们后文分析)

结论2:AutoProxyRegistrar会注入一个类型为InfrastructureAdvisorAutoProxyCreator的bean

3.ProxyTransactionManagementConfiguration源码

这个类比较简单,就是一个配置类,利用@Configuration + @Bean的组合,创建了几个bean

结论3:ProxyTransactionManagementConfiguration会注入beanClass为BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor的三个bean

小结

@EnableTransactionManagement注解会import一个实现ImportSelector接口的类,import的类会注入两个bean(beanClass分别为AutoProxyRegistrar和ProxyTransactionManagementConfiguration),其中AutoProxyRegistrar会进一步解析,然后注入一个类型为InfrastructureAdvisorAutoProxyCreator的bpp。ProxyTransactionManagementConfiguration是一个配置类,会注入几个bean,协助@EnableTransactionManagement注解完成相关功能

2.什么是BeanPostProcessor

BeanPostProcessor从本质上说,它也是一个bean,不过它优先实例化,然后作用于普通bean。比如我们耳熟能详的属性注入、动态代理,都是BeanPostProcessor在不同阶段对普通bean进行的处理。

详情阅读下方链接博文
Spring之BeanPostProcessoricon-default.png?t=N7T8https://blog.csdn.net/qq_38257958/article/details/134753005?spm=1001.2014.3001.5502

3.InfrastructureAdvisorAutoProxyCreator的作用

InfrastructureAdvisorAutoProxyCreator继承BeanPostProcessor,在spring执行到postProcessAfterInitialization的时候会查找可以作用于当前bean的Advisors,如果存在符合条件的Advisors,则进行动态代理

具体查找过程可以查看下方链接博文。简单来说就是查找普通bean所属的class和方法上有没有@Transactional注解,如果满足条件则进行AOP动态代理。Spring之AOP源码解析(下)icon-default.png?t=N7T8https://blog.csdn.net/qq_38257958/article/details/136182213?spm=1001.2014.3001.5502

根据我们设置的参数,有可能进行JDK动态代理也有可能进行cglib动态代理,如果是JDK动态代理我们关注JdkDynamicAopProxy这个类,如果是cglib动态代理我们关注DynamicAdvisedInterceptor这个类。不管是什么动态代理都会有一个field(advised),这个参数存储了可以作用于当前bean的Advisors,每个Advisor都有一个advice对象(MethodInterceptor的父接口),Spring会将这些advice串成一个拦截器链,链式调用各个拦截器的invoke方法,我们画图演示流程

PS:有兴趣的小伙伴可以把我写的几篇关于AOP的文章都阅读一下,可以更好的帮助我们理解这篇博文。

 4.TransactionInterceptor源码

主要关注其invoke方法,invoke方法主要调用了invokeWithinTransaction方法

主体流程

    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {// 上文分析的ProxyTransactionManagementConfiguration注入的三个bean之一(AnnotationTransactionAttributeSource)TransactionAttributeSource tas = getTransactionAttributeSource();// 1.从类上查找@Transactional注解// 2.从方法上查找@Transactional注解// 3.将步骤1或2查找到的@Transactional注解进行解析,构建成TransactionAttribute对象(RuleBasedTransactionAttribute)final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);// 1.如果txAttr为null或者beanFactory为null,返回注入的TransactionManager// 2.如果txAttr.getQualifier不为null(即Transactional注解的value属性值),则从beanFactory获取配置的bean返回// 3.如果注入了transactionManagerBeanName则从beanFactory获取bean返回// 4.如果没注入TransactionManager,就从beanFactory获取class为PlatformTransactionManager的bean返回final TransactionManager tm = determineTransactionManager(txAttr);// 省略webFlux相关代码PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// 开启事务(如果需要)TransactionAspectSupport.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// 执行下一个拦截器的invoke方法或者目标方法retVal = invocation.proceedWithInvocation();} catch (Throwable ex) {// 处理异常completeTransactionAfterThrowing(txInfo, ex);throw ex;} finally {// 解除线程和事务的绑定关系cleanupTransactionInfo(txInfo);}if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...TransactionStatus status = txInfo.getTransactionStatus();if (status != null && txAttr != null) {retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}// 提交事务commitTransactionAfterReturning(txInfo);return retVal;}}
  1. 基础数据准备
    1. 获取TransactionAttributeSource
    2. 获取TransactionAttribute
    3. 推断TransactionManager
  2. 开启事务
  3. 执行拦截器方法或者目标方法
  4. 处理异常(如果存在)
  5. 提交事务

事务同步管理器TransactionSynchronizationManager

这个类在@Transactional源码中起着重要作用,它不仅管理每个线程的资源和事务同步,也协助完成与mybatis的集成

开启事务

TransactionAspectSupport#createTransactionIfNecessary

AbstractPlatformTransactionManager#getTransaction

AbstractPlatformTransactionManager#startTransaction

DataSourceTransactionManager#doBegin

    protected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject) transaction;Connection con = null;try {// 如果事务还没有获取Connection或者Connection还没标记为与事务同步if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {// 获取ConnectionConnection newCon = obtainDataSource().getConnection();if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}// 将Connection标记为new ConnectiontxObject.setConnectionHolder(new ConnectionHolder(newCon), true);}// 将Connection没标记为与事务同步txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con = txObject.getConnectionHolder().getConnection();// 设置事务的隔离级别Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);txObject.setReadOnly(definition.isReadOnly());// 将Connection的自动提交关闭if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}con.setAutoCommit(false);}prepareTransactionalConnection(con, definition);// 将事务标记为已激活txObject.getConnectionHolder().setTransactionActive(true);// 设置过期时间(如果手动设置了)int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 如果是新连接,事务同步管理器同步资源if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, obtainDataSource());txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}

PS : Spring源码中存在很多模板模式,很多方法都是交给子类去实现,比如上文中的doGetTransaction,isExistingTransaction,doBegin等方法,如果我们不确定具体走的是那个子类,可以多多去debug看看。这里TransactionManager主要是子类DataSourceTransactionManager

注意:我们在mysql中开启事务,可以使用BEGIN、START TRANSACTION等,但是在源码中,我们并没有发现这样的sql语句。其实事务可以隐式开启,在上述doBegin方法的源码中,存在con.setAutoCommit(false)这样的方法,其实这就等价于执行sql语句set autocommit = OFF(隐式开启事务)

事务隔离级别

  • REQUIRED
  • SUPPORTS
  • MANDATORY
  • REQUIRES_NEW
  • NOT_SUPPORTED
  • NEVER
  • NESTED

通过源码整理事务处理流程

异常处理

TransactionAspectSupport#completeTransactionAfterThrowing

我们在上文中指出该TransactionAttribute类型为RuleBasedTransactionAttribut,然后如果我们指定@Transactional注解的rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName属性,后期会被解析成RollbackRuleAttribute对象,相关源码明细可以查看AbstractFallbackTransactionAttributeSource(AnnotationTransactionAttributeSource的父类)的getTransactionAttribute方法

case1:未指定rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName

当我们未指定上述四个属性,会调用super.rollbackOn的方法

当我们未指定rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName属性的时候,事务只有在遇到RuntimeException异常或者Error的时候才会回滚

case2:指定rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName

当我们指定了四个属性中的一个或者多个,就会被解析成RollbackRuleAttribute(NoRollbackRuleAttribute),最后通过getDepth方法获取winner,如果winner是RollbackRuleAttribute旧回滚,否则就提交事务

getDepth方法主要判断抛出的异常与指定的异常之间的关系

  • 如果抛出异常和指定异常一致,则depth为0
  • 如果抛出异常和指定异常子类,则depth加1(递归判断)
  • 如果抛出异常为Throwable,则depth为-1

depth值越小(大于0),优先级越高

触发器

不管最后事务是提交还是回滚,都会执行相应的触发器方法,我们可以利用这一特性,做一些扩展

与mybatis的整合

mybatis相关接口会被JDK动态代理,代理对象的类型是MapperProxy。感兴趣小伙伴可以阅读我之前的博文 《@MapperScan源码解析》

MapperProxy#invoke

PlainMethodInvoker#invokeMapperMethod#executeSqlSessionTemplate#selectOne
SqlSessionInterceptor#invoke(sqlSessionProxy是一个代理对象,所以会进入相应拦截器方法)SqlSessionUtils#getSqlSession 

我们看到了我们熟悉的TransactionSynchronizationManager,当mybatis执行sql的时候会从事务同步管理器里面获取resource,保证了同个事务里面的增删改查都是使用的同一个SqlSession

http://www.tj-hxxt.cn/news/50629.html

相关文章:

  • 上海珍岛做网站怎么样企业网站建设方案
  • seo网站系统seo站内优化
  • 做网站时如何建立栅格重庆企业免费建站
  • 广告设计专业技能有哪些西安seo外包服务
  • 优秀的公司网站免费培训课程
  • 手机端网站优化市场营销毕业后做什么工作
  • 广州市地铁站地图廊坊优化技巧
  • php网站 怎么做授权现在最好的免费的建站平台
  • 无限容量网站域名注册查询软件
  • 电子商务法搜索引擎优化概述
  • 查看邮箱注册了哪些网站百度免费注册
  • 成都网站建设公司地址百度热议怎么上首页
  • 网站300兆是多少钱互联网seo是什么
  • seo 网站地图抖音广告投放代理商
  • 北京酷站科技有限公司百度产品优化排名软件
  • 佛山门户网站建设市场营销方案怎么写
  • 使用cn域名做网站的多吗沈阳专业seo关键词优化
  • 本地做网站图片怎么存seo关键词首页排名
  • 织梦可以做论坛网站吗郑州seo优化培训
  • 深圳做网站商关键词歌词林俊杰
  • 自己做的网站怎么设置关键词网络优化工作内容
  • 做境外碎片化旅游的网站台州seo优化
  • 做服装的外贸网站南京今天重大新闻事件
  • 软件下载网站整站源码黄山网络推广公司
  • 番禺区画册设计公司整站优化cms
  • 做外贸比较好的网站爱站网关键词查询工具
  • phpcms wap网站搭建百度竞价最低点击一次多少钱
  • 服务类的网站怎么做今日刚刚发生的国际新闻
  • 企业营销型网站建设价格杭州seo排名优化
  • 没有网站也可以做外贸吗网站关键词推广优化