com
后边一般来说是公司名称了呀。
上图的 1 是后来的,后来者居上嘛, pxhTransactionManager
是没有问题的,因为好名字 transactionManager
已经被我们占了嘛(首发除了探坑还是有好处的),问题应该就出在了又定义了一次 <tx:annotation-driven>
标签。
这里边挺奇怪的,一般大家在工程中就直接是 <tx:annotation-driven/>
声明下这个注解就行了,为啥还要写 transaction-manager
属性呢,这里我们推测(其实就是这样)这是指定事务的默认的管理器,既然是默认那就有个默认的名字,没错如大家所想默认的名字就是 transactionManager
,其实 IDEA
已经给我们提示了,如下图
无用的声明默认属性,而且鼠标放上去 Alt+Enter
第一个提示是可以删除的
定义多次 tx
标签就是很奇怪的事情,这可以在单例天下的 Spring
中,而且我们根据结果和代码可以猜测, <tx:annotation-driven>
标签采取的是 先入为主
的策略,导致我们默认调用的事务管理器变成了 pxhTransactionManager
,然而这并不是我们代码需要调用的数据源,所以回滚无效
猜测必须要以代码为依据,既然标签是定义在 XML
文件中的,那么我们就从 Spring
解析我们的配置文件开始看起,我们从 Spring
在 Web.xml
文件中定义的启动窗口开始,就是大家都知道的 ContextLoaderListener
Listener
均是 ServletContextListener
的实现类在容器启动的时候自行执行 contextInitialized
方法,进入 contextLoader.initWebApplicationContext
方法
这个方法主要是初始化容器上下文,具体的 bean
加载等方法在 configureAndRefreshWebApplicationContext()
方法中
进入 wac.refresh()
方法,这里的 wac
是类是 XmlWebApplicationContext
,上边的就不说了,太烦了没看懂……
XmlWebApplicationContext
这个类的继承很复杂,这里的 refresh()
实际的代码在 AbstractApplicationContext
类中
直奔主题进入 obtainFreshBeanFactory()
方法
loadBeanDefinitions(beanFactory)
方法解析 XML
文件,进入 AbstractXmlApplicationContext
类中的 loadBeanDefinitions()
方法中
进入 XmlWebApplicationContext.loadBeanDefinitions()
方法
进入 AbstractBeanDefinitionReader.loadBeanDefinitions()
的一系列重载方法,然后进入 AbstractBeanDefinitionReader
类的 loadBeanDefinitions(String location, Set<Resource> actualResources)
方法
进入 XmlBeanDefinitionReader
类的 loadBeanDefinitions(EncodedResource encodedResource)
方法
经过 XmlBeanDefinitionReader
类的 doLoadBeanDefinitions()
方法进入 registerBeanDefinitions()
方法,
进入 DefaultBeanDefinitionDocumentReader
类的 registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法
然后进入 parseBeanDefinitions()
方法
像 tx: 这样的标签属于自定义标签走 BeanDefinitionParserDelegate.parseCustomElement()
方法
重点在于通过命名空间找到对应的处理类,进入 DefaultNamespaceHandlerResolver
类的 resolve()
方法
下边是 handlerMappings
命名空间和处理类的对应关系
进入 TxNamespaceHandler
类,可以看出来初始化了几个关键的类
回到刚才的入口,进入 NamespaceHandlerSupport.parse()
方法
可以看出来需要执行 AnnotationDrivenBeanDefinitionParser.parse()
方法
可以发现我们熟悉的包都有身影出现,这里我们猜也是工厂模式的一种了,这里其实就是各种需要引入命名空间的标签的处理类了。我们需要进入的是 spring-tx
包,在 AnnotationDrivenBeanDefinitionParser
的内部静态类 AopAutoProxyConfigurer
的静态方法 configureAutoProxyCreator
是关键,这边也解释了为什么先入为主,
只有当不存在这个类型的 bean
的时候,才会对 bean
初始化并且注册到容器中,而 xml
解析是从上到下的,所以我们被放在下边的事务管理器并不会起到应有的作用,而是被无情的抛弃。
同样在这部分的代码解释了 transaction-manager
标签属性的解析过程,默认值也是在此设置的
在 TransactionInterceptor
类的 invoke()
方法是事务代理对象的具体执行者,具体的代码在 TransactionAspectSupport.invokeWithinTransaction()
类,
上图的 completeTransactionAfterThrowing
方法,决定了在什么异常发生时回滚,如果 @Transactional
注解没有指定 rollbackFor
属性的话,就进入 DefaultTransactionAttribute
,s所以只会在 RuntimeException
类型异常和 Error
时回滚