修缮之前的博文

pull/28/head
AmyliaY 5 years ago
parent 289fa63ab4
commit dd753a604b

@ -23,11 +23,11 @@
### SpringMVC
- [温习一下 servlet](/docs/Spring/SpringMVC/温习一下servlet.md)
- [IoC 容器在 Web 环境中的启动](/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md)
- [IoC容器 在 Web环境 中的启动](/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md)
- [SpringMVC 的设计与实现](/docs/Spring/SpringMVC/SpringMVC的设计与实现.md)
- [SpringMVC 跨域解析](/docs/Spring/SpringMVC/SpringMVC-CROS.md)
### SpringJDBC
努力编写中...
- 努力编写中...
### Spring事务
- [Spring 与事务处理](/docs/Spring/SpringTransaction/Spring与事务处理.md)
@ -87,13 +87,13 @@
- [把被说烂的 BIO、NIO、AIO 再从头到尾扯一遍](docs/Netty/IO/把被说烂的BIO、NIO、AIO再从头到尾扯一遍.md)
### 设计原理
努力编写中...
- 努力编写中...
## Redis
努力编写中...
- 努力编写中...
## Tomcat
努力编写中...
- 努力编写中...
## 学习心得
### 个人经验

@ -1,18 +1,18 @@
JavaEE应用中的事务处理是一个重要并且涉及范围很广的领域。事务管理的实现往往涉及并发和数据一致性方面的问题。作为应用平台的Spring具有在多种环境中配置和使用事务处理的能力也就是说通过使用Spring的事务组件可以把事务处理的工作统一起来并为事务处理提供通用的支持。
JavaEE应用 中的事务处理是一个重要并且涉及范围很广的领域。事务管理的实现往往涉及并发和数据一致性方面的问题。作为应用平台的 Spring具有在多种环境中配置和使用事务处理的能力也就是说通过使用 Spring 的事务组件,可以把事务处理的工作统一起来,并为事务处理提供通用的支持。
在涉及单个数据库局部事务的事务处理中事务的最终实现和数据库的支持是紧密相关的。对局部数据库事务来说一个事务处理的操作单元往往对应着一系列的数据库操作。数据库产品对这些数据库的SQL操作已经提供了原子性的支持对SQL操作而言,它的操作结果有两种: 一种是提交成功,数据库操作成功;另一种是回滚,数据库操作不成功,恢复到操作以前的状态。
在涉及单个数据库局部事务的事务处理中,事务的最终实现和数据库的支持是紧密相关的。对局部数据库事务来说,一个事务处理的操作单元往往对应着一系列的数据库操作。数据库产品对这些数据库的 SQL操作 已经提供了原子性的支持,对 SQL操作 而言,它的操作结果有两种: 一种是提交成功,数据库操作成功;另一种是回滚,数据库操作不成功,恢复到操作以前的状态。
在事务处理中事务处理单元的设计与相应的业务逻辑设计有很紧密的联系。在很多情况下一个业务逻辑处理不会只有一个单独的数据库操作而是有一组数据库操作。在这个处理过程中首先涉及的是事务处理单元划分的问题Spring借助IoC容器的强大配置能力为应用提供了声明式的事务划分方式这种声明式的事务处理为Spring应用使用事务管理提供了统一的方式。有了Spring事务管理的支持只需要通过一些简单的配置应用就能完成复杂的事务处理工作从而为用户使用事务处理提供很大的方便。
## 1 Spring事务处理的设计概览
Spring事务处理模块的类层次结构如下图所示。
在事务处理中事务处理单元的设计与相应的业务逻辑设计有很紧密的联系。在很多情况下一个业务逻辑处理不会只有一个单独的数据库操作而是有一组数据库操作。在这个处理过程中首先涉及的是事务处理单元划分的问题Spring 借助 IoC容器 的强大配置能力,为应用提供了声明式的事务划分方式,这种声明式的事务处理,为 Spring应用 使用事务管理提供了统一的方式。有了 Spring事务管理 的支持,只需要通过一些简单的配置,应用就能完成复杂的事务处理工作,从而为用户使用事务处理提供很大的方便。
## 1 Spring事务处理 的设计概览
Spring事务处理模块 的类层次结构如下图所示。
![avatar](/images/springTransaction/Spring事务处理模块类层次结构.png)
从上图可以看到Spring事务处理模块是通过AOP功能来实现声明式事务处理的比如事务属性的配置和读取事务对象的抽象等。因此在Spring事务处理中可以通过设计一个TransactionProxyFactoryBean来使用AOP功能通过这个TransactionProxyFactoryBean可以生成Proxy代理对象在这个代理对象中通过TransactionInterceptor来完成对代理方法的拦截正是这些AOP的拦截功能将事务处理的功能编织进来。
从上图可以看到Spring事务处理模块 是通过 AOP功能 来实现声明式事务处理的,比如事务属性的配置和读取,事务对象的抽象等。因此,在 Spring事务处理 中,可以通过设计一个 TransactionProxyFactoryBean 来使用 AOP功能通过这个 TransactionProxyFactoryBean 可以生成 Proxy代理对象在这个代理对象中通过 TransactionInterceptor 来完成对代理方法的拦截,正是这些 AOP 的拦截功能,将事务处理的功能编织进来。
对于具体的事务处理实现比如事务的生成、提交、回滚、挂起等由于不同的底层数据库有不同的支持方式因此在Spring事务处理中对主要的事务实现做了一个抽象和适配。适配的具体事务处理器包括对DataSource数据源的事务处理支持对Hibernate数据源的事务处理支持对JDO数据源的事务处理支持对JPA和JTA等数据源的事务处理支持等。这一系列的事务处理支持都是通过设计PlatformTransactionManager、AbstractPlatforTransactionManager以及一系列具体事务处理器来实现的而PlatformTransactionManager又实现了TransactionInterceptor接口通过这样一个接口实现设计就把这一系列的事务处理的实现与前面提到的TransactionProxyFactoryBean结合起来从而形成了一个Spring声明式事务处理的设计体系。
对于具体的事务处理实现,比如事务的生成、提交、回滚、挂起等,由于不同的底层数据库有不同的支持方式,因此,在 Spring事务处理中对主要的事务实现做了一个抽象和适配。适配的具体事务处理器包括 DataSource数据源 的事务处理支持,对 Hibernate数据源 的事务处理支持,对 JDO数据源 的事务处理支持,对 JPA JTA 等数据源的事务处理支持等。这一系列的事务处理支持,都是通过设计 PlatformTransactionManager、AbstractPlatformTransactionManager 以及一系列具体事务处理器来实现的,而 PlatformTransactionManager 又实现了 TransactionInterceptor接口通过这样一个接口实现设计就把这一系列的事务处理的实现与前面提到的 TransactionProxyFactoryBean 结合起来,从而形成了一个 Spring声明式事务处理 的设计体系。
## 2 Spring事务处理的应用场景
Spring作为应用平台或框架的设计出发点是支持POJO的开发这点在实现事务处理的时候也不例外。在Spring中它既支持编程式事务管理方式又支持声明式事务处理方式在使用Spring处理事务的时候声明式事务处理通常比编程式事务管理更方便些。
## 2 Spring事务处理 的应用场景
Spring 作为应用平台或框架的设计出发点是支持 POJO的开发这点在实现事务处理的时候也不例外。在 Spring 中,它既支持编程式事务管理方式,又支持声明式事务处理方式,在使用 Spring 处理事务的时候,声明式事务处理通常比编程式事务管理更方便些。
Spring对应用的支持一方面通过声明式事务处理将事务处理的过程和业务代码分离出来。这种声明方式实际上是通过AOP的方式来完成的。显然Spring已经把那些通用的事务处理过程抽象出来并通过AOP的方式进行封装然后用声明式的使用方式交付给客户使用。这样应用程序可以更简单地管理事务并且只需要关注事务的处理策略。另一方面应用在选择数据源时可能会采取不同的方案当以Spring作为平台时Spring在应用和具体的数据源之间搭建一个中间平台通过这个中间平台解耦应用和具体数据源之间的绑定并且Spring为常用的数据源的事务处理支持提供了一系列的TransactionManager。这些Spring封装好的TransactionManager为应用提供了很大的方便因为在这些具体事务处理过程中已经根据底层的实现封装好了事务处理的设置以及与特定数据源相关的特定事务处理过程这样应用在使用不同的数据源时可以做到事务处理的即开即用。这样的另一个好处是如果应用有其他的数据源事务处理需要Spring也提供了一种一致的方式。这种有机的事务过程抽象和具体的事务处理相结合的设计是我们在日常的开发中非常需要模仿学习的。
Spring 对应用的支持,一方面,通过声明式事务处理,将事务处理的过程和业务代码分离出来。这种声明方式实际上是通过 AOP 的方式来完成的。显然Spring 已经把那些通用的事务处理过程抽象出来,并通过 AOP 的方式进行封装,然后用声明式的使用方式交付给客户使用。这样,应用程序可以更简单地管理事务,并且只需要关注事务的处理策略。另一方面,应用在选择数据源时可能会采取不同的方案,当以 Spring 作为平台时Spring 在应用和具体的数据源之间搭建一个中间平台通过这个中间平台解耦应用和具体数据源之间的绑定并且Spring 为常用的数据源的事务处理支持提供了一系列的 TransactionManager。这些 Spring 封装好的 TransactionManager 为应用提供了很大的方便,因为在这些具体事务处理过程中,已经根据底层的实现,封装好了事务处理的设置以及与特定数据源相关的特定事务处理过程,这样应用在使用不同的数据源时,可以做到事务处理的即开即用。这样的另一个好处是,如果应用有其他的数据源事务处理需要, Spring 也提供了一种一致的方式。这种 有机的事务过程抽象 和 具体的事务处理 相结合的设计,是我们在日常的开发中非常需要模仿学习的。事务处理将事务处理的过程和业务代码分离出来。这种声明方式实际上是通过AOP的方式来完成的。显然Spring已经把那些通用的事务处理过程抽象出来并通过AOP的方式进行封装然后用声明式的使用方式交付给客户使用。这样应用程序可以更简单地管理事务并且只需要关注事务的处理策略。另一方面应用在选择数据源时可能会采取不同的方案当以Spring作为平台时Spring在应用和具体的数据源之间搭建一个中间平台通过这个中间平台解耦应用和具体数据源之间的绑定并且Spring为常用的数据源的事务处理支持提供了一系列的TransactionManager。这些Spring封装好的TransactionManager为应用提供了很大的方便因为在这些具体事务处理过程中已经根据底层的实现封装好了事务处理的设置以及与特定数据源相关的特定事务处理过程这样应用在使用不同的数据源时可以做到事务处理的即开即用。这样的另一个好处是如果应用有其他的数据源事务处理需要Spring也提供了一种一致的方式。这种有机的事务过程抽象和具体的事务处理相结合的设计是我们在日常的开发中非常需要模仿学习的。

@ -1,25 +1,25 @@
## 1 设计原理与基本过程
在使用Spring声明式事务处理的时候一种常用的方法是结合IoC容器和Spring已有的TransactionProxyFactoryBean对事务管理进行配置比如可以在这个TransactionProxyFactoryBean中为事务方法配置传播行为、并发事务隔离级别等事务处理属性从而对声明式事务的处理提供指导。具体来说在对声明式事务处理的原理分析中声明式事务处理的实现大致可以分为以下几个部分:
在使用 Spring声明式事务处理 的时候,一种常用的方法是结合 IoC容器 Spring 已有的 TransactionProxyFactoryBean 对事务管理进行配置,比如,可以在这个 TransactionProxyFactoryBean 中为事务方法配置传播行为、并发事务隔离级别等事务处理属性,从而对声明式事务的处理提供指导。具体来说,在对声明式事务处理的原理分析中,声明式事务处理的实现大致可以分为以下几个部分:
- 读取和处理在IoC容器中配置的事务处理属性并转化为Spring事务处理需要的内部数据结构这里涉及的类是TransactionAttributeSourceAdvisor从名字可以看出它是一个AOP通知器Spring使用这个通知器来完成对事务处理属性值的处理。处理的结果是在IoC容器中配置的事务处理属性信息会被读入并转化成TransactionAttribute表示的数据对象这个数据对象是Spring对事物处理属性值的数据抽象对这些属性的处理是和TransactionProxyFactoryBean拦截下来的事务方法的处理结合起来的。
- Spring事务处理模块实现统一的事务处理过程。这个通用的事务处理过程包含处理事务配置属性以及与线程绑定完成事务处理的过程Spring通过TransactionInfo和TransactionStatus这两个数据对象在事务处理过程中记录和传递相关执行场景。
- 底层的事务处理实现。对于底层的事务操作Spring委托给具体的事务处理器来完成这些具体的事务处理器就是在IoC容器中配置声明式事务处理时配置的PlatformTransactionManager的具体实现比如DataSourceTransactionManager和HibernateTransactionManager等。
- 读取和处理在 IoC容器 中配置的事务处理属性,并转化为 Spring事务处理 需要的内部数据结构,这里涉及的类是 TransactionAttributeSourceAdvisor从名字可以看出它是一个 AOP通知器Spring 使用这个通知器来完成对事务处理属性值的处理。处理的结果是,在 IoC容器 中配置的事务处理属性信息,会被读入并转化成 TransactionAttribute 表示的数据对象,这个数据对象是 Spring 对事物处理属性值的数据抽象,对这些属性的处理是和 TransactionProxyFactoryBean 拦截下来的事务方法的处理结合起来的。
- Spring事务处理模块 实现统一的事务处理过程。这个通用的事务处理过程包含处理事务配置属性以及与线程绑定完成事务处理的过程Spring 通过 TransactionInfo TransactionStatus 这两个数据对象,在事务处理过程中记录和传递相关执行场景。
- 底层的事务处理实现。对于底层的事务操作Spring 委托给具体的事务处理器来完成,这些具体的事务处理器,就是在 IoC容器 中配置声明式事务处理时,配置的 PlatformTransactionManager 的具体实现,比如 DataSourceTransactionManager HibernateTransactionManager 等。
## 2 实现分析
### 2.1 事务处理拦截器的配置
和前面的思路一样从声明式事务处理的基本用法入手来了解它的基本实现原理。在使用声明式事务处理的时候需要在IoC容器中配置TransactionProxyFactoryBean见名知义这是一个FactoryBean有一个getObject()方法。在IoC容器进行注入的时候会创建TransactionInterceptor对象而这个对象会创建一个TransactionAttributePointcut为读取TransactionAttribute做准备。在容器初始化的过程中由于实现了InitializingBean接口因此AbstractSingletonProxyFactoryBean会实现afterPropertiesSet()方法正是在这个方法实例化了一个ProxyFactory建立起Spring AOP的应用在这里会为这个ProxyFactory设置通知、目标对象并最终返回Proxy代理对象。在Proxy代理对象建立起来以后在调用其代理方法的时候会调用相应的TransactionInterceptor拦截器在这个调用中会根据TransactionAttribute配置的事务属性进行配置从而为事务处理做好准备。
和前面的思路一样,从声明式事务处理的基本用法入手,来了解它的基本实现原理。在使用声明式事务处理的时候,需要在 IoC容器 中配置 TransactionProxyFactoryBean见名知义这是一个 FactoryBean有一个 getObject()方法。在 IoC容器 进行注入的时候,会创建 TransactionInterceptor对象而这个对象会创建一个 TransactionAttributePointcut为读取 TransactionAttribute 做准备。在容器初始化的过程中,由于实现了 InitializingBean接口因此 AbstractSingletonProxyFactoryBean 会实现 afterPropertiesSet()方法,正是在这个方法实例化了一个 ProxyFactory建立起 Spring AOP 的应用,在这里,会为这个 ProxyFactory 设置通知、目标对象,并最终返回 Proxy代理对象。在 Proxy代理对象 建立起来以后,在调用其代理方法的时候,会调用相应的 TransactionInterceptor拦截器在这个调用中会根据 TransactionAttribute 配置的事务属性进行配置,从而为事务处理做好准备。
从TransactionProxyFactoryBean入手通过代码实现来了解Spring是如何通过AOP功能来完成事务管理配置的Spring为声明式事务处理的实现所做的一些准备工作包括为AOP配置基础设施这些基础设施包括设置拦截器TransactionInterceptor、通知器DefaultPointcutAdvisor或TransactionAttributeSourceAdvisor。同时在TransactionProxyFactoryBean的实现中 还可以看到注人进来的PlatformTransactionManager和事务处理属性TransactionAttribute等。
TransactionProxyFactoryBean 入手,通过代码实现来了解 Spring 是如何通过 AOP功能 来完成事务管理配置的Spring 为声明式事务处理的实现所做的一些准备工作:包括为 AOP 配置基础设施,这些基础设施包括设置 拦截器TransactionInterceptor、通知器DefaultPointcutAdvisor TransactionAttributeSourceAdvisor。同时 TransactionProxyFactoryBean 的实现中, 还可以看到注人进来的 PlatformTransactionManager 事务处理属性TransactionAttribute 等。
```java
/**
* 代理工厂bean用于简化声明式事务处理,这是标准AOP的一个方便的替代方案
* 代理工厂bean 用于简化声明式事务处理,这是标准 AOP 的一个方便的替代方案
* 使用单独的TransactionInterceptor定义。
*/
@SuppressWarnings("serial")
public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean
implements BeanFactoryAware {
/** 事务拦截器通过AOP来发挥作用spring在此拦截器中封装了 事务处理实现 */
/** 事务拦截器,通过 AOP 来发挥作用Spring 在此拦截器中封装了事务处理实现 */
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
/** 切面 */
@ -27,16 +27,16 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe
/**
* 通过依赖注入的事务属性以properties的形式出现
* 把从beandefinition中读到的事务管理的属性信息注入到transactionInterceptor
* 通过依赖注入的事务属性以 properties的形式 出现
* 把从 beandefinition 中读到的事务管理的属性信息注入到 transactionInterceptor
*/
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionInterceptor.setTransactionManager(transactionManager);
}
/**
* 创建AOP对事务处理的advisor
* 本方法在IoC容器完成Bean的依赖注入时通过initializeBean方法被调用
* 创建 AOP 对事务处理的 advisor
* 本方法在 IoC容器 完成 Bean的依赖注入时通过 initializeBean()方法 被调用
*/
@Override
protected Object createMainInterceptor() {
@ -46,7 +46,7 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
}
else {
// 如果没定义则使用spring默认的切面使用TransactionAttributeSourceAdvisor
// 如果没定义,则使用 Spring默认的切面使用 TransactionAttributeSourceAdvisor
// 作为通知器,并配置拦截器
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
}
@ -69,11 +69,11 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe
}
}
```
以上代码完成了AOP配置对于用户来说一个值得关心的问题是Spring的TransactionInterceptor配置是在什么时候被启动并成为Advisor通知器的一部分的呢从对createMainInterceptor()方法的调用分析中可以看到这个createMainInterceptor()方法在IoC容器完成Bean的依赖注入时通过initializeBean()方法被调用,具体的调用过程如下图所示。
以上代码完成了 AOP配置对于用户来说一个值得关心的问题是Spring TransactionInterceptor配置 是在什么时候被启动并成为 Advisor通知器 的一部分的呢?从对 createMainInterceptor()方法 的调用分析中可以看到,这个 createMainInterceptor()方法 IoC容器 完成 Bean的依赖注入时通过 initializeBean()方法 被调用,具体的调用过程如下图所示。
![avatar](/images/springTransaction/createMainInterceptor()方法的调用链.png)
在TransactionProxyFactoryBean的父类AbstractSingletonProxyFactoryBean中的afterPropertiesSet()方法是Spring事务处理完成AOP配置的地方在建立TransactionProxyFactoryBean的事务处理拦截器的时候首先需要对ProxyFactoryBean的目标Bean设置进行检查如果这个目标Bean的设置是正确的就会创建一个ProxyFactory对象从而实现AOP的使用。在afterPropertiesSet()的方法实现中可以看到为ProxyFactory生成代理对象、配置通知器、设置代理接口方法等。
TransactionProxyFactoryBean 的父类 AbstractSingletonProxyFactoryBean 中的 afterPropertiesSet()方法,是 Spring事务处理 完成 AOP配置 的地方,在建立 TransactionProxyFactoryBean 的事务处理拦截器的时候,首先需要对 ProxyFactoryBean 目标Bean 设置进行检查,如果这个 目标Bean 的设置是正确的,就会创建一个 ProxyFactory对象从而实现 AOP 的使用。在 afterPropertiesSet() 的方法实现中,可以看到为 ProxyFactory 生成代理对象、配置通知器、设置代理接口方法等。
```java
public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanClassLoaderAware, InitializingBean {
@ -94,7 +94,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
private Object proxy;
/**
* 处理完成AOP配置创建ProxyFactory对象为其生成代理对象
* 处理完成 AOP配置创建 ProxyFactory对象为其生成代理对象
* 配置通知器、设置代理接口方法
*/
public void afterPropertiesSet() {
@ -110,8 +110,8 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
}
// 使用ProxyFactory完成AOP的基本功能ProxyFactory提供proxy对象
// 并将TransactionIntercepter设为target方法调用的拦截器
// 使用 ProxyFactory 完成 AOP的基本功能ProxyFactory 提供 proxy对象
// 并将 TransactionIntercepter 设为 target方法调用的拦截器
ProxyFactory proxyFactory = new ProxyFactory();
if (this.preInterceptors != null) {
@ -120,12 +120,12 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
}
}
// 加入Advisor通知器可以加入两种通知器分别是
// 加入 Advisor通知器可以加入两种通知器分别是
// DefaultPointcutAdvisor、TransactionAttributeSourceAdvisor
// 这里通过调用TransactionProxyFactoryBean实例的createMainInterceptor()方法
// 来生成需要的Advisors。在ProxyFactory的基类AdvisedSupport中维护了一个持有Advisor
// 这里通过调用 TransactionProxyFactoryBean实例 的 createMainInterceptor()方法
// 来生成需要的 Advisors。在 ProxyFactory 的基类 AdvisedSupport 中维护了一个持有 Advisor
// 的链表LinkedList<Advisor>,通过对这个链表中的元素执行增、删、改等操作,用来管理
// 配置给ProxyFactory的通知器
// 配置给 ProxyFactory 的通知器
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
if (this.postInterceptors != null) {
@ -136,7 +136,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
proxyFactory.copyFrom(this);
// 这里创建AOP的目标源与在其它地方使用ProxyFactory没什么差别
// 这里创建 AOP 的目标源,与在其它地方使用 ProxyFactory 没什么差别
TargetSource targetSource = createTargetSource(this.target);
proxyFactory.setTargetSource(targetSource);
@ -144,7 +144,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
proxyFactory.setInterfaces(this.proxyInterfaces);
}
else if (!isProxyTargetClass()) {
// 需要根据AOP基础设施来确定使用哪个接口作为代理
// 需要根据 AOP 基础设施来确定使用哪个接口作为代理
proxyFactory.setInterfaces(
ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
}
@ -154,24 +154,24 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
}
}
```
DefaultAopProxyFactory创建AOP Proxy的过程在前面分析AOP的实现原理时已分析过这里就不再重复了。可以看到通过以上的一系列步骤Spring为实现事务处理而设计的拦截器TransctionInterceptor已经设置到ProxyFactory生成的AOP代理对象中去了这里的TransactionInterceptor是作为AOP Advice的拦截器来实现它的功能的。在IoC容器中配置其他与事务处理有关的属性比如比较熟悉的transactionManager和事务处理的属性也同样会被设置到已经定义好的TransactionInterceptor中去。这些属性配置在TransactionInterceptor对事务方法进行拦截时会起作用。在AOP配置完成以后可以看到在Spring声明式事务处理实现中的一些重要的类已经悄然登场比如TransactionAttributeSourceAdvisor和TransactionInterceptor正是这些类通过AOP封装了Spring对事务处理的基本实现。
DefaultAopProxyFactory 创建 AOP Proxy 的过程在前面分析 AOP的实现原理 时已分析过这里就不再重复了。可以看到通过以上的一系列步骤Spring 为实现事务处理而设计的 拦截器TransctionInterceptor 已经设置到 ProxyFactory 生成的 AOP代理对象 中去了,这里的 TransactionInterceptor 是作为 AOP Advice 的拦截器来实现它的功能的。在 IoC容器 中,配置其他与事务处理有关的属性,比如,比较熟悉的 transactionManager 和事务处理的属性,也同样会被设置到已经定义好的 TransactionInterceptor 中去。这些属性配置在 TransactionInterceptor对事务方法进行拦截时会起作用。在 AOP配置 完成以后,可以看到,在 Spring声明式事务处理实现 中的一些重要的类已经悄然登场,比如 TransactionAttributeSourceAdvisor TransactionInterceptor正是这些类通过 AOP 封装了 Spring 对事务处理的基本实现。
### 2.2 事务处理配置的读入
在AOP配置完成的基础上以TransactionAttributeSourceAdvisor的实现为入 口,了解具体的事务属性配置是如何读入的。
AOP配置 完成的基础上,以 TransactionAttributeSourceAdvisor的实现 为入口,了解具体的事务属性配置是如何读入的。
```java
public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
/**
* 与其它Advisor一样同样需要定义AOP中用到的Interceptor和Pointcut
* 与其它 Advisor 一样,同样需要定义 AOP 中用到的 Interceptor 和 Pointcut
*/
private TransactionInterceptor transactionInterceptor;
/**
* 对于切面pointcut这里使用了一个匿名内部类
* 对于 切面Pointcut这里使用了一个匿名内部类
*/
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
/**
* 通过transactionInterceptor来得到事务的配置属性在对Proxy的方法进行匹配调用时,
* 通过 transactionInterceptor 来得到事务的配置属性,在对 Proxy的方法 进行匹配调用时,
* 会使用到这些配置属性
*/
@Override
@ -181,7 +181,7 @@ public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
};
}
```
在声明式事务处理中通过对目标对象的方法调用进行拦截来实现事务处理的织入这个拦截通过AOP发挥作用。在AOP中对于拦截的启动首先需要对方法调用是否需要拦截进行判断而判断的依据是那些在TransactionProxyFactoryBean中为目标对象设置的事务属性。也就是说需要判断当前的目标方法调用是不是一个配置好的并且需要进行事务处理的方法调用。具体来说这个匹配判断在TransactionAttributeSourcePointcut的matches()方法中完成,该方法实现 首先把事务方法的属性配置读取到TransactionAttributeSource对象中有了这些事务处理的配置以后根据当前方法调用的Method对象和目标对象对是否需要启动事务处理拦截器进行判断。
在声明式事务处理中,通过对目标对象的方法调用进行拦截来实现事务处理的织入,这个拦截通过 AOP 发挥作用。在 AOP 中,对于拦截的启动,首先需要对方法调用是否需要拦截进行判断,而判断的依据是那些在 TransactionProxyFactoryBean 中为目标对象设置的事务属性。也就是说,需要判断当前的目标方法调用是不是一个配置好的并且需要进行事务处理的方法调用。具体来说,这个匹配判断在 TransactionAttributeSourcePointcut matches()方法 中完成,该方法实现 首先把事务方法的属性配置读取到 TransactionAttributeSource对象 中,有了这些事务处理的配置以后,根据当前方法调用的 Method对象 目标对象,对是否需要启动事务处理拦截器进行判断。
```java
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@ -191,33 +191,33 @@ abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPoi
}
}
```
在Pointcut的matches()判断过程中会用到TransactionAttributeSource对象这个TransactionAttributeSource对象是在对TransactionInterceptor进行依赖注入时就配置好的。它的设置是在TransactionInterceptor的基类TransactionAspectSupport中完成的配置的是一个NameMatchTransactionAttributeSource对象。
Pointcut matches()判断过程 中,会用到 TransactionAttributeSource对象这个 TransactionAttributeSource对象 是在对 TransactionInterceptor 进行依赖注入时就配置好的。它的设置是在 TransactionInterceptor 的基类 TransactionAspectSupport 中完成的,配置的是一个 NameMatchTransactionAttributeSource对象。
```java
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
/**
* 设置事务属性以方法名为key事务属性描述符为value
* 设置事务属性,以方法名为 key事务属性描述符为 value
* 例如key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly"
*/
public void setTransactionAttributes(Properties transactionAttributes) {
// 可以看到这是一个NameMatchTransactionAttributeSource的实现
// 可以看到这是一个 NameMatchTransactionAttributeSource 的实现
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
}
```
在以上的代码实现中可以看到NameMatchTransactionAttributeSource作为TransactionAttributeSource的具体实现是实际完成事务处理属性读入和匹配的地方。在对事务属性TransactionAttributes进行设置时会从事务处理属性配置中读取事务方法名和配置属性在得到配置的事务方法名和属性以后会把它们作为键值对加入到一个nameMap中。
在以上的代码实现中可以看到NameMatchTransactionAttributeSource 作为 TransactionAttributeSource 的具体实现,是实际完成事务处理属性读入和匹配的地方。在对 事务属性TransactionAttributes 进行设置时,会从事务处理属性配置中读取事务方法名和配置属性,在得到配置的事务方法名和属性以后,会把它们作为键值对加入到一个 nameMap 中。
在应用调用目标方法的时候因为这个目标方法已经被TransactionProxyFactoryBean代理所以TransactionProxyFactoryBean需要判断这个调用方法是否是事务方法。这个判断的实现是通过在NameMatchTransactionAttributeSource中能否为这个调用方法返回事务属性来完成的。具体的实现过程是这样的首先以调用方法名为索引在nameMap中查找相应的事务处理属性值如果能够找到那么就说明该调用方法和事务方法是直接对应的如果找不到那么就会遍历整个nameMap对保存在nameMap中的每一个方法名使用PatternMatchUtils的simpleMatch()方法进行命名模式上的匹配。这里使用PatternMatchUtils进行匹配的原因是在设置事务方法的时候可以不需要为事务方法设置一个完整的方法名而可以通过设置方法名的命名模式来完成比如可以通过对通配符*的使用等。所以如果直接通过方法名没能够匹配上而通过方法名的命名模式能够匹配上这个方法也是需要进行事务处理的相对应地它所配置的事务处理属性也会从nameMap中取出来从而触发事务处理拦截器的拦截。
在应用调用目标方法的时候,因为这个目标方法已经被 TransactionProxyFactoryBean 代理,所以 TransactionProxyFactoryBean 需要判断这个调用方法是否是事务方法。这个判断的实现,是通过在 NameMatchTransactionAttributeSource 中能否为这个调用方法返回事务属性来完成的。具体的实现过程是这样的:首先,以调用方法名为索引在 nameMap 中查找相应的事务处理属性值,如果能够找到,那么就说明该调用方法和事务方法是直接对应的,如果找不到,那么就会遍历整个 nameMap对保存在 nameMap 中的每一个方法名,使用 PatternMatchUtils的simpleMatch()方法 进行命名模式上的匹配。这里使用 PatternMatchUtils 进行匹配的原因是,在设置事务方法的时候,可以不需要为事务方法设置一个完整的方法名,而可以通过设置方法名的命名模式来完成,比如可以通过对 通配符* 的使用等。所以,如果直接通过方法名没能够匹配上,而通过方法名的命名模式能够匹配上,这个方法也是需要进行事务处理的,相对应地,它所配置的事务处理属性也会从 nameMap 中取出来,从而触发事务处理拦截器的拦截。
```java
public class NameMatchTransactionAttributeSource implements TransactionAttributeSource, Serializable {
/** key是方法名value是事务属性 */
/** key 是方法名value 是事务属性 */
private Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>();
/**
* 将给定属性transactionAttributes解析为名称/属性的map对象。以 方法名称 为键
* 字符串属性定义 为值可通过TransactionAttributeEditor解析为TransactionAttribute实例。
* 将给定 属性transactionAttributes 解析为 <名称, 属性> 的Map对象。以 方法名称 为 key
* 字符串属性定义 为 value可通过 TransactionAttributeEditor 解析为 TransactionAttribute实例。
*/
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
@ -270,17 +270,18 @@ public class NameMatchTransactionAttributeSource implements TransactionAttribute
protected boolean isMatch(String methodName, String mappedName) {
return PatternMatchUtils.simpleMatch(mappedName, methodName);
}
}
```
通过以上过程可以得到与目标对象调用方法相关的TransactionAttribute对象在这个对象中封装了事务处理的配置。具体来说在前面的匹配过程中如果匹配返回的结果是null那么说明当前的调用方法不是一个事务方法不需要纳入Spring统一的事务管理中因为它并没有配置在TransactionProxyFactoryBean的事务处理设置中。如果返回的TransactionAttribute对象不是null,那么这个返回的TransactionAttribute对象就已经包含了对事务方法的配置信息对应这个事务方法的具体事务配置也已经读入到TransactionAttribute对象中了为TransactionInterceptor做好了对调用的目标方法添加事务处理的准备。
通过以上过程可以得到与目标对象调用方法相关的 TransactionAttribute对象在这个对象中封装了事务处理的配置。具体来说在前面的匹配过程中如果匹配返回的结果是 null那么说明当前的调用方法不是一个事务方法不需要纳入 Spring 统一的事务管理中,因为它并没有配置在 TransactionProxyFactoryBean 的事务处理设置中。如果返回的 TransactionAttribute对象 不是 null,那么这个返回的 TransactionAttribute对象 就已经包含了对事务方法的配置信息,对应这个事务方法的具体事务配置也已经读入到 TransactionAttribute对象 中了,为 TransactionInterceptor 做好了对调用的目标方法添加事务处理的准备。
### 2.3 事务处理拦截器的设计与实现
在完成以上的准备工作后经过TransactionProxyFactoryBean的AOP包装 此时如果对目标对象进行方法调用起作用的对象实际上是一个Proxy代理对象对目标对象方法的调用不会直接作用在TransactionProxyFactoryBean设置的目标对象上而会被设置的事务处理拦截器拦截。而在TransactionProxyFactoryBean的AOP实现中获取Proxy对象的过程并不复杂TransactionProxyFactoryBean作为一个FactoryBean对这个Bean的对象的引用是通过调用其父类AbstractSingletonProxyFactoryBean的getObject()方法来得到的。
在完成以上的准备工作后,经过 TransactionProxyFactoryBean AOP包装 此时如果对目标对象进行方法调用,起作用的对象实际上是一个 Proxy代理对象对目标对象方法的调用不会直接作用在 TransactionProxyFactoryBean 设置的目标对象上,而会被设置的事务处理拦截器拦截。而在 TransactionProxyFactoryBean AOP实现 中,获取 Proxy对象 的过程并不复杂TransactionProxyFactoryBean 作为一个 FactoryBean对这个 Bean 的对象的引用是通过调用其父类 AbstractSingletonProxyFactoryBean getObject()方法 来得到的。
```java
public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanClassLoaderAware, InitializingBean {
private Object proxy;
// 返回的是一个proxy代理对象这个proxy是ProxyFactory生成的AOP代理
// 返回的是一个 proxy代理对象这个 proxy 是 ProxyFactory 生成的 AOP代理
// 已经封装了对事务处理的拦截器配置
public Object getObject() {
if (this.proxy == null) {
@ -290,7 +291,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
}
}
```
InvocationHandler的实现类中有一个非常重要的方法invoke()该方法是proxy代理对象的回调方法在调用proxy对象的代理方法时触发这个回调。事务处理拦截器TransactionInterceptor中实现了InvocationHandler的invoke()方法其过程是首先获得调用方法的事务处理配置在得到事务处理配置以后会取得配置的PlatformTransactionManager由这个事务处理器来实现事务的创建、提交、回滚操作。
InvocationHandler 的实现类中有一个非常重要的方法 invoke(),该方法是 proxy代理对象 的回调方法,在调用 proxy对象 的代理方法时触发这个回调。事务处理拦截器TransactionInterceptor 中实现了 InvocationHandler invoke()方法,其过程是,首先获得调用方法的事务处理配置;在得到事务处理配置以后,会取得配置的 PlatformTransactionManager由这个事务处理器来实现事务的创建、提交、回滚操作。
```java
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@ -298,7 +299,7 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
// 得到代理的目标对象,并将事务属性传递给目标对象
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 在其父类TransactionAspectSupport中进行后续的事务处理
// 在其父类 TransactionAspectSupport 中进行后续的事务处理
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
@ -320,13 +321,13 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
// 这里区分不同类型的PlatformTransactionManager因为他们的调用方式不同
// 对CallbackPreferringPlatformTransactionManager来说,需要回调函数
// 来实现事务的创建和提交,而非CallbackPreferringPlatformTransactionManager
// 这里区分不同类型的 PlatformTransactionManager因为他们的调用方式不同
// 对 CallbackPreferringPlatformTransactionManager 来说,需要回调函数
// 来实现事务的创建和提交,而非 CallbackPreferringPlatformTransactionManager
// 则不需要
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 这里创建事务同时把创建事务过程中得到的信息放到TransactionInfo中
// TransactionInfo是保存当前事务状态的对象
// 这里创建事务,同时把创建事务过程中得到的信息放到 TransactionInfo 中,
// TransactionInfo 是保存当前事务状态的对象
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
@ -340,7 +341,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
throw ex;
}
finally {
// 这里把 与线程绑定的TransactionInfo设置为oldTransactionInfo
// 这里把 与线程绑定的 TransactionInfo 设置为 oldTransactionInfo
cleanupTransactionInfo(txInfo);
}
// 这里通过事务处理器来对事务进行提交
@ -358,7 +359,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// RuntimeException会导致事务回滚
// RuntimeException 会导致事务回滚
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
@ -415,9 +416,9 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
}
}
```
以事务提交为例简要的说明下该过程。在调用代理的事务方法时因为前面已经完成了一系列AOP配置对事务方法的调用最终启动
TransactionInterceptor拦截器的invoke()方法。在这个方法中首先会读取该事务方法的事务属性配置然后根据事务属性配置以及具体事务处理器的配置来决定采用哪一个事务处理器这个事务处理器实际上是一个PlatformTransactionManager。在确定好具体的事务处理器之后会根据事务的运行情况和事务配置来决定是不是需要创建新的事务。
以事务提交为例,简要的说明下该过程。在调用代理的事务方法时,因为前面已经完成了一系列 AOP配置对事务方法的调用最终启动
TransactionInterceptor拦截器 invoke()方法。在这个方法中,首先会读取该事务方法的事务属性配置,然后根据事务属性配置以及具体事务处理器的配置来决定采用哪一个事务处理器,这个事务处理器实际上是一个 PlatformTransactionManager。在确定好具体的事务处理器之后会根据事务的运行情况和事务配置来决定是不是需要创建新的事务。
对于Spring而言事务的管理实际上是通过一个TransactionInfo对象来完成的在该对象中封装了事务对象和事务处理的状态信息这是事务处理的抽象。在这一步完成以后会对拦截器链进行处理因为有可能在该事务对象中还配置了除事务处理AOP之外的其他拦截器。在结束对拦截器链处理之后会对TransactionInfo中的信息进行更新以反映最近的事务处理情况在这个时候也就完成了事务提交的准备通过调用事务处理器PlatformTransactionManager的commitTransactionAfterReturning()方法来完成事务的提交。这个提交的处理过程已经封装在PlatformTransactionManager的事务处理器中了而与具体数据源相关的处理过程最终委托给相关的具体事务处理器来完成比如DataSourceTransactionManager、Hibermate'TransactionManager等。
对于 Spring 而言,事务的管理实际上是通过一个 TransactionInfo对象 来完成的,在该对象中,封装了事务对象和事务处理的状态信息,这是事务处理的抽象。在这一步完成以后,会对拦截器链进行处理,因为有可能在该事务对象中还配置了除事务处理 AOP 之外的其他拦截器。在结束对拦截器链处理之后,会对 TransactionInfo 中的信息进行更新,以反映最近的事务处理情况,在这个时候,也就完成了事务提交的准备,通过调用 事务处理器PlatformTransactionManager commitTransactionAfterReturning()方法 来完成事务的提交。这个提交的处理过程已经封装在 PlatformTransactionManager 的事务处理器中了,而与具体数据源相关的处理过程,最终委托给相关的具体事务处理器来完成,比如 DataSourceTransactionManager、Hibermate'TransactionManager 等。
在这个invoke()方法的实现中可以看到整个事务处理在AOP拦截器中实现的全过程。同时它也是Spring采用AOP封装事务处理和实现声明式事务处理的核心部分。这部分实现是一个桥梁它胶合了具体的事务处理和Spring AOP框架可以看成是一个Spring AOP应用在这个桥梁搭建完成以后Spring事务处理的实现就开始了。
在这个 invoke()方法 的实现中,可以看到整个事务处理在 AOP拦截器 中实现的全过程。同时,它也是 Spring 采用 AOP 封装事务处理和实现声明式事务处理的核心部分。这部分实现是一个桥梁,它胶合了具体的事务处理和 Spring AOP框架可以看成是一个 Spring AOP应用在这个桥梁搭建完成以后Spring事务处理 的实现就开始了。
Loading…
Cancel
Save