spring源码分析之事物

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取 2000+ 道 Java 面试题

我们看看Spring中的事务处理的代码,使用Spring管理事务有声明式和编程式两种方式,声明式事务处理通过AOP的实现把事物管理代码作为方面封装来横向插入到业务代码中,使得事务管理代码和业务代码解藕。在这种方式我们结合IoC容器和Spirng已有的FactoryBean来对事务管理进行属性配置,比如传播行为,隔离级别等。其中最简单的方式就是通过配置TransactionProxyFactoryBean来实现声明式事物;
在整个源代码分析中,我们可以大致可以看到Spring实现声明式事物管理有这么几个部分:

* 对在上下文中配置的属性的处理,这里涉及的类是TransactionAttributeSourceAdvisor,这是一个通知器,用它来对属性值进行处理,属性信息放在TransactionAttribute中来使用,而这些属性的处理往往是和对切入点的处理是结合起来的。对属性的处理放在类TransactionAttributeSource中完成。
* 创建事物的过程,这个过程是委托给具体的事物管理器来创建的,但Spring通过TransactionStatus来传递相关的信息。
* 对事物的处理通过对相关信息的判断来委托给具体的事物管理器完成。

我们下面看看具体的实现,在TransactionFactoryBean中:

Java代码

  1. publicclass TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean
  2. implements FactoryBean, BeanFactoryAware {
  3. //这里是Spring事务处理而使用的AOP拦截器,中间封装了Spring对事务处理的代码来支持声明式事务处理的实现
  4. privatefinal TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
  5. private Pointcut pointcut;
  6. //这里Spring把TransactionManager注入到TransactionInterceptor中去
  7. publicvoid setTransactionManager(PlatformTransactionManager transactionManager) {
  8. this.transactionInterceptor.setTransactionManager(transactionManager);
  9. }
  10. //这里把在bean配置文件中读到的事务管理的属性信息注入到TransactionInterceptor中去
  11. publicvoid setTransactionAttributes(Properties transactionAttributes) {
  12. this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
  13. }
  14. ………中间省略了其他一些方法…….
  15. //这里创建Spring AOP对事务处理的Advisor
  16. protected Object createMainInterceptor() {
  17. this.transactionInterceptor.afterPropertiesSet();
  18. if (this.pointcut != null) {
  19. //这里使用默认的通知器
  20. returnnew DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
  21. }
  22. else {
  23. // 使用上面定义好的TransactionInterceptor作为拦截器,同时使用TransactionAttributeSourceAdvisor
  24. returnnew TransactionAttributeSourceAdvisor(this.transactionInterceptor);
  25. }
  26. }
  27. }

那什么时候Spring的TransactionInterceptor被注入到Spring AOP中成为Advisor中的一部分呢?我们看到在TransactionProxyFactoryBean中,这个方法在IOC初始化bean的时候被执行:

Java代码

  1. publicvoid afterPropertiesSet() {
  2. …….
  3. //TransactionProxyFactoryBean实际上使用ProxyFactory完成AOP的基本功能。
  4. ProxyFactory proxyFactory = new ProxyFactory();
  5. if (this.preInterceptors != null) {
  6. for (int i = 0; i < this.preInterceptors.length; i++) {
  7. proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));
  8. }
  9. }
  10. //这里是Spring加入通知器的地方
  11. //有两种通知器可以被加入DefaultPointcutAdvisor或者TransactionAttributeSourceAdvisor
  12. //这里把Spring处理声明式事务处理的AOP代码都放到ProxyFactory中去,怎样加入advisor我们可以参考ProxyFactory的父类AdvisedSupport()
  13. //由它来维护一个advice的链表,通过这个链表的增删改来抽象我们对整个通知器配置的增删改操作。
  14. proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
  15. if (this.postInterceptors != null) {
  16. for (int i = 0; i < this.postInterceptors.length; i++) {
  17. proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));
  18. }
  19. }
  20. proxyFactory.copyFrom(this);
  21. //这里创建AOP的目标源
  22. TargetSource targetSource = createTargetSource(this.target);
  23. proxyFactory.setTargetSource(targetSource);
  24. if (this.proxyInterfaces != null) {
  25. proxyFactory.setInterfaces(this.proxyInterfaces);
  26. }
  27. elseif (!isProxyTargetClass()) {
  28. proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));
  29. }
  30. this.proxy = getProxy(proxyFactory);
  31. }

Spring 已经定义了一个transctionInterceptor作为拦截器或者AOP advice的实现,在IOC容器中定义的其他属性比如transactionManager和事务管理的属性都会传到已经定义好的 TransactionInterceptor那里去进行处理。以上反映了基本的Spring AOP的定义过程,其中pointcut和advice都已经定义好,同时也通过通知器配置到ProxyFactory中去了。
下面让我们回到TransactionProxyFactoryBean中看看TransactionAttributeSourceAdvisor是怎样定义的,这样我们可以理解具体的属性是怎样起作用,这里我们分析一下类TransactionAttributeSourceAdvisor:

Java代码

  1. publicclass TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
  2. //和其他Advisor一样,同样需要定义AOP中的用到的Interceptor和Pointcut
  3. //Interceptor使用传进来的TransactionInterceptor
  4. //而对于pointcut,这里定义了一个内部类,参见下面的代码
  5. private TransactionInterceptor transactionInterceptor;
  6. privatefinal TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();
  7. ………
  8. //定义的PointCut内部类
  9. privateclass TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
  10. …….
  11. //方法匹配的实现,使用了TransactionAttributeSource类
  12. publicboolean matches(Method method, Class targetClass) {
  13. TransactionAttributeSource tas = getTransactionAttributeSource();
  14. //这里使用TransactionAttributeSource来对配置属性进行处理
  15. return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);
  16. }
  17. ……..省略了equal,hashcode,tostring的代码
  18. }

这里我们看看属性值是怎样被读入的:AbstractFallbackTransactionAttributeSource负责具体的属性读入任务,我们可以有两种读入方式,比如annotation和直接配置.我们下面看看直接配置的读入方式,在Spring中同时对读入的属性值进行了缓存处理,这是一个decorator模式:

Java代码

  1. publicfinal TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
  2. //这里先查一下缓存里有没有事务管理的属性配置,如果有从缓存中取得TransactionAttribute
  3. Object cacheKey = getCacheKey(method, targetClass);
  4. Object cached = this.cache.get(cacheKey);
  5. if (cached != null) {
  6. if (cached == NULL_TRANSACTION_ATTRIBUTE) {
  7. returnnull;
  8. }
  9. else {
  10. return (TransactionAttribute) cached;
  11. }
  12. }
  13. else {
  14. // 这里通过对方法和目标对象的信息来计算事务缓存属性
  15. TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
  16. //把得到的事务缓存属性存到缓存中,下次可以直接从缓存中取得。
  17. if (txAtt == null) {
  18. this.cache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
  19. }
  20. else {
  21. ………..
  22. this.cache.put(cacheKey, txAtt);
  23. }
  24. return txAtt;
  25. }
  26. }

别急,基本的处理在computeTransactionAttribute()中:

Java代码

  1. private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {
  2. //这里检测是不是public方法
  3. if(allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
  4. returnnull;
  5. }
  6. Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
  7. // First try is the method in the target class.
  8. TransactionAttribute txAtt = findTransactionAttribute(findAllAttributes(specificMethod));
  9. if (txAtt != null) {
  10. return txAtt;
  11. }
  12. // Second try is the transaction attribute on the target class.
  13. txAtt = findTransactionAttribute(findAllAttributes(specificMethod.getDeclaringClass()));
  14. if (txAtt != null) {
  15. return txAtt;
  16. }
  17. if (specificMethod != method) {
  18. // Fallback is to look at the original method.
  19. txAtt = findTransactionAttribute(findAllAttributes(method));
  20. if (txAtt != null) {
  21. return txAtt;
  22. }
  23. // Last fallback is the class of the original method.
  24. return findTransactionAttribute(findAllAttributes(method.getDeclaringClass()));
  25. }
  26. returnnull;
  27. }

经过一系列的尝试我们可以通过findTransactionAttribute()通过调用findAllAttribute()得到TransactionAttribute的对象,如果返回的是null,这说明该方法不是我们需要事务处理的方法。
在完成把需要的通知器加到ProxyFactory中去的基础上,我们看看具体的看事务处理代码怎样起作用,在TransactionInterceptor中:

Java代码

  1. public Object invoke(final MethodInvocation invocation) throws Throwable {
  2. //这里得到目标对象
  3. Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
  4. //这里同样的通过判断是否能够得到TransactionAttribute来决定是否对当前方法进行事务处理,有可能该属性已经被缓存,
  5. //具体可以参考上面对getTransactionAttribute的分析,同样是通过TransactionAttributeSource
  6. final TransactionAttribute txAttr =
  7. getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
  8. final String joinpointIdentification = methodIdentification(invocation.getMethod());
  9. //这里判断我们使用了什么TransactionManager
  10. if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
  11. // 这里创建事务,同时把创建事务过程中得到的信息放到TransactionInfo中去
  12. TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
  13. Object retVal = null;
  14. try {
  15. retVal = invocation.proceed();
  16. }
  17. catch (Throwable ex) {
  18. // target invocation exception
  19. completeTransactionAfterThrowing(txInfo, ex);
  20. throw ex;
  21. }
  22. finally {
  23. cleanupTransactionInfo(txInfo);
  24. }
  25. commitTransactionAfterReturning(txInfo);
  26. return retVal;
  27. }
  28. else {
  29. // 使用的是Spring定义的PlatformTransactionManager同时实现了回调接口,我们通过其回调函数完成事务处理,就像我们使用编程式事务处理一样。
  30. try {
  31. Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
  32. new TransactionCallback() {
  33. public Object doInTransaction(TransactionStatus status) {
  34. //同样的需要一个TransactonInfo
  35. TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
  36. try {
  37. return invocation.proceed();
  38. }
  39. …..这里省去了异常处理和事务信息的清理代码
  40. });
  41. ………..
  42. }
  43. }

这里面涉及到事务的创建,我们可以在TransactionAspectSupport实现的事务管理代码:

Java代码

  1. protected TransactionInfo createTransactionIfNecessary(
  2. TransactionAttribute txAttr, final String joinpointIdentification) {
  3. // If no name specified, apply method identification as transaction name.
  4. if (txAttr != null && txAttr.getName() == null) {
  5. txAttr = new DelegatingTransactionAttribute(txAttr) {
  6. public String getName() {
  7. return joinpointIdentification;
  8. }
  9. };
  10. }
  11. TransactionStatus status = null;
  12. if (txAttr != null) {
  13. //这里使用了我们定义好的事务配置信息,有事务管理器来创建事务,同时返回TransactionInfo
  14. status = getTransactionManager().getTransaction(txAttr);
  15. }
  16. return prepareTransactionInfo(txAttr, joinpointIdentification, status);
  17. }

首先通过TransactionManager得到需要的事务,事务的创建根据我们定义的事务配置决定,在 AbstractTransactionManager中给出一个标准的创建过程,当然创建什么样的事务还是需要具体的 PlatformTransactionManager来决定,但这里给出了创建事务的模板:

Java代码

  1. publicfinal TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
  2. Object transaction = doGetTransaction();
  3. ……
  4. if (definition == null) {
  5. //如果事务信息没有被配置,我们使用Spring默认的配置方式
  6. definition = new DefaultTransactionDefinition();
  7. }
  8. if (isExistingTransaction(transaction)) {
  9. // Existing transaction found -> check propagation behavior to find out how to behave.
  10. return handleExistingTransaction(definition, transaction, debugEnabled);
  11. }
  12. // Check definition settings for new transaction.
  13. //下面就是使用配置信息来创建我们需要的事务;比如传播属性和同步属性等
  14. //最后把创建过程中的信息收集起来放到TransactionStatus中返回;
  15. if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
  16. thrownew InvalidTimeoutException(“Invalid transaction timeout”, definition.getTimeout());
  17. }
  18. // No existing transaction found -> check propagation behavior to find out how to behave.
  19. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
  20. thrownew IllegalTransactionStateException(
  21. “Transaction propagation ‘mandatory’ but no existing transaction found”);
  22. }
  23. elseif (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
  24. definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
  25. definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
  26. //这里是事务管理器创建事务的地方,并将创建过程中得到的信息放到TransactionStatus中去,包括创建出来的事务
  27. doBegin(transaction, definition);
  28. boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
  29. return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
  30. }
  31. else {
  32. boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
  33. return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);
  34. }
  35. }

接着通过调用prepareTransactionInfo完成事务创建的准备,创建过程中得到的信息存储在TransactionInfo对象中进行传递同时把信息和当前线程绑定;

Java代码

  1. protected TransactionInfo prepareTransactionInfo(
  2. TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
  3. TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification);
  4. if (txAttr != null) {
  5. …..
  6. // 同样的需要把在getTransaction中得到的TransactionStatus放到TransactionInfo中来。
  7. txInfo.newTransactionStatus(status);
  8. }
  9. else {
  10. …….
  11. }
  12. // 绑定事务创建信息到当前线程
  13. txInfo.bindToThread();
  14. return txInfo;
  15. }

将创建事务的信息返回,然后看到其他的事务管理代码:

Java代码

  1. protectedvoid commitTransactionAfterReturning(TransactionInfo txInfo) {
  2. if (txInfo != null && txInfo.hasTransaction()) {
  3. if (logger.isDebugEnabled()) {
  4. logger.debug(“Invoking commit for transaction on “ + txInfo.getJoinpointIdentification());
  5. }
  6. this.transactionManager.commit(txInfo.getTransactionStatus());
  7. }
  8. }

通过transactionManager对事务进行处理,包括异常抛出和正常的提交事务,具体的事务管理器由用户程序设定。

Java代码

  1. protectedvoid completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
  2. if (txInfo != null && txInfo.hasTransaction()) {
  3. if (txInfo.transactionAttribute.rollbackOn(ex)) {
  4. ……
  5. try {
  6. this.transactionManager.rollback(txInfo.getTransactionStatus());
  7. }
  8. ……….
  9. }
  10. else {
  11. ………
  12. try {
  13. this.transactionManager.commit(txInfo.getTransactionStatus());
  14. }
  15. ………..
  16. }
  17. protectedvoid commitTransactionAfterReturning(TransactionInfo txInfo) {
  18. if (txInfo != null && txInfo.hasTransaction()) {
  19. ……
  20. this.transactionManager.commit(txInfo.getTransactionStatus());
  21. }
  22. }

Spring通过以上代码对transactionManager进行事务处理的过程进行了AOP包装,到这里我们看到为了方便客户实现声明式的事务处理,Spring还是做了许多工作的。如果说使用编程式事务处理,过程其实比较清楚,我们可以参考书中的例子:

Java代码

  1. TransactionDefinition td = new DefaultTransactionDefinition();
  2. TransactionStatus status = transactionManager.getTransaction(td);
  3. try{
  4. ……//这里是我们的业务方法
  5. }catch (ApplicationException e) {
  6. transactionManager.rollback(status);
  7. throw e
  8. }
  9. transactionManager.commit(status);
  10. ……..

我们看到这里选取了默认的事务配置DefaultTransactionDefinition,同时在创建事物的过程中得到TransactionStatus,然后通过直接调用事务管理器的相关方法就能完成事务处理。
声明式事务处理也同样实现了类似的过程,只是因为采用了声明的方法,需要增加对属性的读取处理,并且需要把整个过程整合到Spring AOP框架中和IoC容器中去的过程。
下面我们选取一个具体的transactionManager – DataSourceTransactionManager来看看其中事务处理的实现:
同样的通过使用AbstractPlatformTransactionManager使用模板方法,这些都体现了对具体平台相关的事务管理器操作的封装,比如commit:

Java代码

  1. publicfinalvoid commit(TransactionStatus status) throws TransactionException {
  2. ……
  3. DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
  4. if (defStatus.isLocalRollbackOnly()) {
  5. ……
  6. processRollback(defStatus);
  7. return;
  8. }
  9. …….
  10. processRollback(defStatus);
  11. ……
  12. }
  13. processCommit(defStatus);
  14. }

通过对TransactionStatus的具体状态的判断,来决定具体的事务处理:

Java代码

  1. privatevoid processCommit(DefaultTransactionStatus status) throws TransactionException {
  2. try {
  3. boolean beforeCompletionInvoked = false;
  4. try {
  5. triggerBeforeCommit(status);
  6. triggerBeforeCompletion(status);
  7. beforeCompletionInvoked = true;
  8. boolean globalRollbackOnly = false;
  9. if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
  10. globalRollbackOnly = status.isGlobalRollbackOnly();
  11. }
  12. if (status.hasSavepoint()) {
  13. ……..
  14. status.releaseHeldSavepoint();
  15. }
  16. elseif (status.isNewTransaction()) {
  17. ……
  18. doCommit(status);
  19. }
  20. ………
  21. }

这些模板方法的实现由具体的transactionManager来实现,比如在DataSourceTransactionManager:

Java代码

  1. protectedvoid doCommit(DefaultTransactionStatus status) {
  2. //这里得到存在TransactionInfo中已经创建好的事务
  3. DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  4. //这里得到和事务绑定的数据库连接
  5. Connection con = txObject.getConnectionHolder().getConnection();
  6. ……..
  7. try {
  8. //这里通过数据库连接来提交事务
  9. con.commit();
  10. }
  11. …….
  12. }
  13. protectedvoid doRollback(DefaultTransactionStatus status) {
  14. DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  15. Connection con = txObject.getConnectionHolder().getConnection();
  16. if (status.isDebug()) {
  17. logger.debug(“Rolling back JDBC transaction on Connection [“ + con + “]”);
  18. }
  19. try {
  20. //这里通过数据库连接来回滚事务
  21. con.rollback();
  22. }
  23. catch (SQLException ex) {
  24. thrownew TransactionSystemException(“Could not roll back JDBC transaction”, ex);
  25. }
  26. }

来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码分析之事物

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏