spring 源码之事务

声明式事务简单示例

service 实现类

@Service
public class ProductInfoServiceImpl implements ProductInfoService {
    
    

    @Autowired
    private ProductInfoMapper productInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
    @Override
    public void addRequired(ProductInfo productInfo) {
    
    
        productInfoMapper.insert(productInfo);
        throw new RuntimeException("发生异常......");
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 配置 springIOC 容器要管理的Bean(包扫描) -->
    <context:component-scan base-package="com.atguigu">
        <!-- 排除 @Controller 的注解的包,不需要扫描 -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 数据源配置 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;verifyServerCertificate=false&amp;useSSL=false"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <!-- 初始化时获取的连接数,默认是 0 -->
        <property name="initialSize" value="3"/>
        <!-- 连接池中保留的最小线程空闲数,默认为 0 -->
        <property name="minIdle" value="3"/>
        <!-- 连接池中保留的最大线程空闲数,默认为 8 -->
        <property name="maxIdle" value="8"/>
        <!-- 连接池中最大的连接数,默认值: 8 -->
        <property name="maxActive" value="8"/>
        <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
        <property name="maxWait" value="60000"/>
    </bean>

    <!-- spring 和 mybatis 整合 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定 mybatis 要连接的数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- mybatis 配置文件的地址 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- mybatis 的 mapper 文件的地址 -->
        <property name="mapperLocations" value="classpath:com/atguigu/mapper/*.xml"/>
    </bean>

    <!-- 配置 Mapper 接口扫描 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- 配置Spring的事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 开启注解式事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

测试类

public class TransactionTest_1 {
    
    

    @Test
    public void notransaction_exception_required_required() {
    
    
        /* 初始化启动 spring ioc 容器 */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
        /* 从 spring ioc 容器中获取一个 bean */
        ProductInfoService productInfoService = (ProductInfoService) applicationContext.getBean("productInfoServiceImpl");

        BigDecimal bigDecimal = new BigDecimal("1499.00");
        ProductInfo productInfo = new ProductInfo(12, "HUAWEI nova 5z", bigDecimal, 100, "极致体验", 1);
        productInfoService.addRequired(productInfo);// 此方法开启了事务
    }
}

测试结果1

在这里插入图片描述
测试结果2

去除

throw new RuntimeException("发生异常......");

时,结果如下

在这里插入图片描述

spring 事务源码解读

我们首先从配置文件开始入手,在配置文件中配置了 <tx:annotation-driven />。这个配置是事务的开关,如果没有此处配置,那么 spring 光靠 @Transactional 注解不能开启事务的功能。那么我们就从这个配置开始分析

1.spring 事务配置文件的解析

使用开发工具进入 DEBUG 模式,给下面的代码打上断点:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");

1.1.进入类 ClassPathXmlApplicationContext 的构造器:

public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
    
    

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
    
    
			refresh();
		}
}

看一下它的核心方法肯定就在 refresh() 里面,实际上它调用的是抽象类AbstractApplicationContextrefresh()

1.2.AbstractApplicationContextrefresh()方法(重点

@Override
	public void refresh() throws BeansException, IllegalStateException {
    
    
		synchronized (this.startupShutdownMonitor) {
    
    
		
			/**
			 * 刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
			 */
			prepareRefresh();

			// 该方法会解析所有 spring 配置文件(通常我们会放在 resources 目录下)
			// 将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/**
			 * 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
			 * 设置SPEL表达式#{key}的解析器
			 * 设置资源编辑注册器,如PerpertyEditorSupper的支持
			 * 添加ApplicationContextAwareProcessor处理器
			 * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
			 * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
			 */
			prepareBeanFactory(beanFactory);

			try {
    
    
				/**
				 * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
				 * 在当前上下文使用的Bean容器BeanFactory的标准初始化完成后对其做一些修改。此时
				 * 所有的Bean definition都已经加载但是还没有 Bean 被创建
				 */
				postProcessBeanFactory(beanFactory);

				/**
				 * 实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor
				 * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
				 * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				/**
				 * 注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中
				 * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
				 * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
				 */				
				registerBeanPostProcessors(beanFactory);

				// 初始化上下文中的资源文件,如国际化文件的处理等
				initMessageSource();

				// 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
				initApplicationEventMulticaster();

				// 给子类扩展初始化其他Bean
				onRefresh();

				// 注册监听器
				registerListeners();

				/**
				 * 设置转换器
				 * 注册一个默认的属性值解析器
				 * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
				 * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
				 */
				finishBeanFactoryInitialization(beanFactory);

				/**
				 * 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
				 * spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
				 * 启动所有实现了Lifecycle接口的类
				 * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
				 * ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
				 * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
				 */
				finishRefresh();
			}

			catch (BeansException ex) {
    
    
				if (logger.isWarnEnabled()) {
    
    
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
    
    
				resetCommonCaches();
			}
		}
	}

AbstractApplicationContextrefresh()中的重点方法:

  • obtainFreshBeanFactory():解析所有 spring 配置文件,将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory
  • invokeBeanFactoryPostProcessors :提供给开发者对 BeanFactory 进行扩展
  • registerBeanPostProcessors :提供给开发者对 bean 进行扩展
  • finishBeanFactoryInitialization :实例化剩余的所有非懒加载单例 bean

1.3.obtainFreshBeanFactory() 方法

该方法会解析所有 spring 配置文件(通常我们会放在 resources 目录下),将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。鉴于篇幅,关于这个方法本篇不再赘述,可以查看详细介绍,最终会进入方法 parseBeanDefinitions

1.4.类 DefaultBeanDefinitionDocumentReaderparseBeanDefinitions 方法

解析每一个 <bean>...</bean>,或者自定义的标签,如<tx: ...>

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    
    
	
	// 1.默认命名空间的处理 
	if (delegate.isDefaultNamespace(root)) {
    
    
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
    
    
				Node node = nl.item(i);
				if (node instanceof Element) {
    
    
					Element ele = (Element) node;
					// 判断是否是自定义的 bean 的声明
					if (delegate.isDefaultNamespace(ele)) {
    
    
						// 默认命名空间节点的处理,例如: <bean id="test" class="" />
						parseDefaultElement(ele, delegate);
					}
					else {
    
    
						// 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
						delegate.parseCustomElement(ele);
					}
				}
			}
	}
	else {
    
    
		// 2.自定义命名空间的处理
		delegate.parseCustomElement(root);
	}		
}

1.5.DEBUG 模式进入 delegate.parseCustomElement(ele) 方法

@Nullable
public BeanDefinition parseCustomElement(Element ele) {
    
    
	// 调用如下
	return parseCustomElement(ele, null);
}


@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    
    
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
    
    
			return null;
		}
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
    
    
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}		

1.6.进入 resolve() 方法

DefaultNamespaceHandlerResolver 类中

@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
    
    
		
		// 获取所有已配置的 Handler 映射缓存
		Map<String, Object> handlerMappings = getHandlerMappings();
		// 从 handlerMappings 中获取 namespaceUri 对应的 NamespaceHandler 全类名
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
    
    
			return null;
		}
		// 已做过解析的情况下,直接从缓存中获取
		else if (handlerOrClassName instanceof NamespaceHandler) {
    
    
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
    
    
			// 如果没有做过解析,直接返回类路径,进行反射
			String className = (String) handlerOrClassName;
			try {
    
    
				Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
    
    
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
				// 初始化类
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
				// 调用自定义的 namespaceHandler 的初始化方法
				namespaceHandler.init();
				// 记录在 handlerMappings 缓存中
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
    
    
				throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
						"] for namespace [" + namespaceUri + "]", ex);
			}
			catch (LinkageError err) {
    
    
				throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
						className + "] for namespace [" + namespaceUri + "]", err);
			}
		}
}

1.7.进入 namespaceHandler.init() 方法

public class TxNamespaceHandler extends NamespaceHandlerSupport {
    
    

	static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";

	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";


	static String getTransactionManagerName(Element element) {
    
    
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}


	@Override
	public void init() {
    
    
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}
}

我们可以看到 annotation-driven 的解析类是 AnnotationDrivenBeanDefinitionParser

1.8.进入 AnnotationDrivenBeanDefinitionParser 类中查看其 parse() 方法

事务的 annotation-driven 标签的的解析

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    
    
   registerTransactionalEventListenerFactory(parserContext);
   
   // 获取 mode 属性设置
   String mode = element.getAttribute("mode");
   if ("aspectj".equals(mode)) {
    
    
      // mode="aspectj"
      registerTransactionAspect(element, parserContext);
      if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
    
    
         registerJtaTransactionAspect(element, parserContext);
      }
   }
   else {
    
    
      // mode="proxy"
      AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
   }
   return null;
}

<tx:annotation-driven> 一共有四个属性如下:

  • mode:指定 spring 事务管理框架创建通知 bean 的方式。可用的值有 proxyaspectj。前者是默认值,表示通知对象是个 JDK 代理;后者表示 spring aop 会使用 AspectJ 创建代理
  • proxy-target-class:如果为 truespring 将创建子类来代理业务类;如果为 false,则使用基于接口的代理。(如果使用子类代理,需要在类路径中添加 CGLib.jar 类库)
  • order:如果业务类除事务切面外,还需要织入其他的切面,通过该属性可以控制事务切面在目标连接点的织入顺序
  • transaction-manager:指定到现有的 PlatformTransactionManager bean 的引用,通知会使用该引用

parse() 方法主要获取自定义 annotation-driven 标签的 mode 属性值,属性值默认为 proxy,除此之外可以配置成 aspectj

  • proxy 是代理模式,仅在外部方法调用才会被代理截获,自身方法调用,即使配置了 @Transactional注解事务也无法生效,此外代理模式也不能应用在非 public 方法上
  • aspectj 模式与代理模式不同,aspectj 模式可以自身方法调用,也可以应用在非 public 方法上

1.9.进入类 AopAutoProxyConfigurer

在此着重分析代理模式的事务,AopAutoProxyConfigurer 是定义在 AnnotationDrivenBeanDefinitionParser 类中的一个内部类,其内部就一个静态方法。主要就是在容器中注册了四个 bean

private static class AopAutoProxyConfigurer {
    
    

   public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    
    
      // 注册代理类(InfrastructureAdvisorAutoProxyCreator类型的bean)
      AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

      // TRANSACTION_ADVISOR_BEAN_NAME=org.springframework.transaction.config.internalTransactionAdvisor
      String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
      if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
    
    
         Object eleSource = parserContext.extractSource(element);

         // =============创建TransactionAttributeSource类型的bean.==============
         RootBeanDefinition sourceDef = new RootBeanDefinition(
               "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
         sourceDef.setSource(eleSource);
         sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         // 注册bean,并使用Spring中的定义规则生成beanName,返回beanName
         String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

         // =====================创建TransactionInterceptor类型的bean.=====================
         RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
         interceptorDef.setSource(eleSource);
         interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         registerTransactionManager(element, interceptorDef);
         interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
         // 注册bean,并使用Spring中的定义规则生成beanName,返回beanName
         String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

         // ==============创建TransactionAttributeSourceAdvisor类型的bean.================
         RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
         advisorDef.setSource(eleSource);
         advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         // 将sourceName的bean注入advisorDef的transactionAttributeSource属性中
         advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
         // 将interceptorName的bean注入advisorDef的adviceBeanName属性中
         advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
         // 如果配置了order属性,则加入到bean中
         if (element.hasAttribute("order")) {
    
    
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
         }
         // 注册TransactionAttributeSourceAdvisor类型的bean
         parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

         // 创建CompositeComponentDefinition
         CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
         compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
         compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
         compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
         parserContext.registerComponent(compositeDef);
      }
   }
}

注册的四个 bean 分别是:

  • InfrastructureAdvisorAutoProxyCreator:自动代理创建器。事务自定义标签能够调用 AOP 方法的关键
  • TransactionAttributeSource:帮助解析事务注解信息,封装并保存成 TransactionAttribute
  • TransactionInterceptor:事务拦截器。在 AOP 的拦截器调用过程中接触过拦截器的概念,spring 会将所有的拦截器封装成 Advisors,最后会调用拦截器的 invoke() 方法进行目标方法增强等
  • TransactionAttributeSourceAdvisor:事务属性增强器。可见其属于增强器 Advisor 类型,其中可以定义切点表达式相关的内容

2.后置处理器的调用

上一部分我们主要工作就是注册了四个 beanDefinition,最终都会实例化成对应的 bean。我们简单的推测 spring 实现事务的原理,其实是通过 AOP 对我们的 service 方法进行增强,添加一些固定的流程代码,而实现这个逻辑基本和 AOP没有太大的差异,AOP 会在 bean 初始化的时候决定是否进行增强返回代理对象,实现这个功能主要靠的就是 BeanPostProcessor 后处理器接口方法。所以,事务也相似,我们先从 ProductInfoServiceImpl 的实例化代理对象创建着手,去分析事务的功能实现

2.1.ProductInfoServiceImpl 的代理对象创建

鉴于篇幅,本篇文章不再详细赘述 aop 代理对象的产生,可以查看 aop 代理对象的产生,我们直接进入 AbstractAutowireCapableBeanFactoryinitializeBean 方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    
    
		
		// 第一步:先执行所有的AwareMethods
		if (System.getSecurityManager() != null) {
    
    
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    
    
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		} else {
    
    
			// 如果实现了Aware接口,就对该bean进行一些设置
        	// 比如实现了BeanNameAware接口,那么对其bean的属性beanName上设置对应的beanName
        	// 如果实现了BeanFactoryAware接口,那么对其beanFactory属性设置上创建该bean使用的bean工厂
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
    
    
			// 执行所有的BeanPostProcessor#postProcessBeforeInitialization  初始化之前的处理器方法
			// 规则:只要谁反悔了null,后面的就都不要执行了
			// 这里面实现postProcessBeforeInitialization 的处理器就很多了,有很多对Aware进行了扩展的
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
    
    
			// 如果bean实现了InitializingBean或者用户自定义的init方法方法,那么调用这些初始化方法对bean的属性进行一些个性化设置
			invokeInitMethods(beanName, wrappedBean, mbd);
		} catch (Throwable ex) {
    
    
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
    
    
			// 执行后置处理器的postProcessAfterInitialization方法。AOP的原理和实现就在其中
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
}

2.2.后处理器的调用

从代码中可以看出调用后处理器的方法其实是对所有的处理器都调用一遍,对我们构造出的 ProductInfoServiceImplbean 进行挨个后处理

/**
 * 初始化前应用BeanPostProcessors后处理器
 */
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {
    
    

   Object result = existingBean;
   for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    
    
      Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
    
    
         return result;
      }
      result = current;
   }
   return result;
}

/**
 * 初始化后应用BeanPostProcessors后处理器
 */
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {
    
    

   Object result = existingBean;
   for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    
    
      Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
    
    
         return result;
      }
      result = current;
   }
   return result;
}

第一部分的我们注册了一个 bean 后处理器 InfrastructureAdvisorAutoProxyCreator 就在这派上用场了。debug 代码截图如下,此时遍历的 beanProcessor 就是 InfrastructureAdvisorAutoProxyCreator 类型的实例

在这里插入图片描述
2.3.AbstractAutoProxyCreatorpostProcessAfterInitialization() 方法

先看 postProcessAfterInitialization()接口方法,实现该方法是在 InfrastructureAdvisorAutoProxyCreator 的父类 AbstractAutoProxyCreator 中,实现 BeanPostProcessor接口方法,返回代理对象

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    
    
    if (bean != null) {
    
    
        // 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // earlyProxyReferences中缓存的是已经创建好的代理对象
        if (!this.earlyProxyReferences.contains(cacheKey)) {
    
    
        	// 如果它适合被代理,则需要封装指定bean
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

2.4.类 AbstractAutoProxyCreatorwrapIfNecessary 方法

看到这里,应该很熟悉了,之前在分析 AOP 流程的时候,也是这个方法。方法内容也无需多说,主要就是先寻找合适增强器,然后进行增强返回代理类对象

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    
    
    // 也是看看有没有缓存,有缓存对象就直接返回了
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    
    
        return bean;
    }
    // 如果该bean不需要被代理,则直接返回原始的bean对象
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    
    
        return bean;
    }
    
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    
    
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
 	
 	// 获取 bean 的 advices(通知或增强器)
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
    
    
    	// 加入缓存中
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 通过createProxy方法创建代理对象
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
 
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

3.寻找事务类/方法对应的增强器

3.1.跟进 getAdvicesAndAdvisorsForBean 方法

spring 通过 getAdvicesAndAdvisorsForBean() 获取指定 bean 对应的增强器,不但要找出增强器,而且还需要判断增强器是否满足要求

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    
    
	
	// 寻找所有合适的增强器	
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   	if (advisors.isEmpty()) {
    
    
      	return DO_NOT_PROXY;
   	}
   	return advisors.toArray();
}

寻找所有合适的增强器(增强器并不一定都适用于当前 bean,要选出满足我们通配符的增强器)

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    
    

    // 获取所有的增强
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 寻找所有增强中适用于 bean 的增强并应用
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 在advice链的开始添加ExposeInvocationInterceptor
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
    
    
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

上述方法内部过于繁杂,鉴于篇幅,在此省略,详情查看

上述方法的任务是:找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性

现在,我们是以 ProductInfoServiceImpl为例的,已经在它的接口上找到了事务注解,那么自然就返回了不为空的 TransactionAttribute 实例,所以它是与事务增强器匹配的,也就是它会被事务功能修饰

当判断某个 bean 适用于事务增强时,也就是适用于增强器 BeanFactoryTransactionAttributeSourceAdvisor,所以说,在自定义标签解析时,注入的四个 bean 成为了整个事务功能的基础

4.事务增强器(重点

由于我们从容器中获取的 ProductInfoServiceImplJDK 的一个代理对象。因为是JDK动态代理,当调用目标方法时,直接执行 JdkDynamicAopProxy (实现 InvocationHandler 接口) 的 invoke() 方法

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    

	MethodInvocation invocation;
   	Object oldProxy = null;
   	boolean setProxyContext = false;

   	// 包含了原始类对象信息
   	TargetSource targetSource = this.advised.targetSource;
   	Object target = null;

   	try {
    
    
      	// 对 equals方法的处理
      	if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    
    
         	return equals(args[0]);
      	}
      	// 对 hashcode方法的处理
      	else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    
    
         	return hashCode();
      	}
      	else if (method.getDeclaringClass() == DecoratingProxy.class) {
    
    
         	return AopProxyUtils.ultimateTargetClass(this.advised);
      	}
      	// Class类的isAssignableFrom(Class cls)方法:如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,
      	// 或者是参数cls表示的类或接口的父类,则返回true。例如:
      	// System.out.println(ArrayList.class.isAssignableFrom(Object.class));   --> false
      	// System.out.println(Object.class.isAssignableFrom(ArrayList.class));  --> true

      	// 如果 method所在类是Advised父类,则直接调用切点方法
      	else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            	method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    
    
         	return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      	}

      	Object retVal;

      	// 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理至ThreadLocal中
      	if (this.advised.exposeProxy) {
    
    
         	// 将代理类对象proxy保存到ThreadLocal中,同时获取之前存储的oldProxy
         	oldProxy = AopContext.setCurrentProxy(proxy);
         	setProxyContext = true;
      	}

      	// 获取目标对象及类型
      	target = targetSource.getTarget();
      	Class<?> targetClass = (target != null ? target.getClass() : null);

      	// 获取当前方法的拦截器链(之前我们找的增强器统一封装成了拦截器链)
      	List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      	if (chain.isEmpty()) {
    
    
         	// 如果没有发现任何拦截器那么直接调用切点方法
         	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      	}
      	else {
    
    
         	// 将拦截器封装在ReflectiveMethodInvocation,以便于使用下面的 proceed进行链接调用拦截器
         	invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         	// 执行拦截器链中每个拦截器的 invoke 方法
         	retVal = invocation.proceed();
      	}

      	// 返回结果
      	Class<?> returnType = method.getReturnType();
      	if (retVal != null && retVal == target &&
            	returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    
    
         	retVal = proxy;
      	}
      	else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
    
    
         	throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      	}
      	return retVal;
   	}
   	finally {
    
    
      	if (target != null && !targetSource.isStatic()) {
    
    
         	targetSource.releaseTarget(target);
      	}
      	if (setProxyContext) {
    
    
         	AopContext.setCurrentProxy(oldProxy);
      	}
   	}
}

getInterceptorsAndDynamicInterceptionAdvice() 方法获得的拦截器调用链 chain 内容其实只有 TransactionInterceptor 一个,TransactionInterceptor 实现了 MethodInterceptor 接口。最终会调用每个 MethodInterceptorinvoke 方法

随后进行拦截器的逐一调用,调用的其实是:执行拦截器中的 invoke() 方法

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    
    

	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

targetClass 就是 ProductInfoServiceImpl 的全限定类名

4.1.看 invokeWithinTransaction() 方法,其为 spring 事务管理的核心方法(重点

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {
    
    

   	// 1. 获取对应配置的事务属性,事务属性保存在 AnnotationTransactionAttributeSource中
   	TransactionAttributeSource tas = getTransactionAttributeSource();
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   	// 2. 获取 beanFactory 中的 transactionManager
   	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   	// 构造方法唯一标识(类.方法,如xxx.xxx.service.ActorServiceImpl.save)
   	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   	// 3. 对不同的事务处理方式使用不同的逻辑,包括声明式和编程式
   	// 声明式事务处理
   	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    
    

      	// 4. 创建TransactionInfo,在目标方法执行前获取事务并收集事务信息
      	TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      	Object retVal = null;
      	try {
    
    
         	// 5. 执行被增强方法
         	retVal = invocation.proceedWithInvocation();
      	}
      	catch (Throwable ex) {
    
    
         	// 6. 异常回滚
         	completeTransactionAfterThrowing(txInfo, ex);
         	throw ex;
      	}
      	finally {
    
    
         	// 7. 清除信息
         	cleanupTransactionInfo(txInfo);
      	}
      	// 8. 提交事务
      	commitTransactionAfterReturning(txInfo);
      	return retVal;
   	}
   	// 编程式事务处理
   	else {
    
    
      	final ThrowableHolder throwableHolder = new ThrowableHolder();
      	try {
    
    
         		Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
    
    
            	TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
           	 try {
    
    
               	return invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
    
    
               if (txAttr.rollbackOn(ex)) {
    
    
                  if (ex instanceof RuntimeException) {
    
    
                     throw (RuntimeException) ex;
                  }
                  else {
    
    
                     throw new ThrowableHolderException(ex);
                  }
               }
               	else {
    
    
                  	throwableHolder.throwable = ex;
                  	return null;
               	}
            }
            	finally {
    
    
               		cleanupTransactionInfo(txInfo);
            	}
         	});

         	if (throwableHolder.throwable != null) {
    
    
            	throw throwableHolder.throwable;
         	}
         	return result;
      	}
      	catch (ThrowableHolderException ex) {
    
    
         	throw ex.getCause();
      	}
      	catch (TransactionSystemException ex2) {
    
    
         	if (throwableHolder.throwable != null) {
    
    
            	logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
            	ex2.initApplicationException(throwableHolder.throwable);
         	}
         	throw ex2;
      	}
      	catch (Throwable ex2) {
    
    
         	if (throwableHolder.throwable != null) {
    
    
            	logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
         	}
         	throw ex2;
      	}
   	}
}

该方法就是我们需要着重研究的对象,我们尝试整理下事务处理的脉络,在 spring 中支持两种事务处理的方式,分别是声明式事务处理编程式事务处理,两者相对于开发人员来讲差别很大,考虑到对事务的应用比声明式的事务处理使用起来方便,也相对流行些,我们就分析声明式事务

对于声明式的事务处理主要有以下几个步骤:

  1. 获取事务的属性。对于事务处理来说,最基础或者说最首要的工作便是获取事务属性了,这是支撑整个事务功能的基石,在前面我们已经分析了事务属性提取,保存在了 AnnotationTransactionAttributeSource
  2. 加载配置文件中配置的 TransactionManager
  3. 不同的事务处理方式使用不同的逻辑。主要是声明式事务和编程式事务之分
  4. 创建 TransactionInfo,在目标方法执行前获取事务并收集事务信息
  5. 执行目标(被代理类的)方法。注意该方法的调用时机
  6. 一旦出现异常,尝试异常处理。并不是所有异常,spring 都会将其回滚,默认只对 RuntimeExceptionError 两种情况会进行回滚处理
  7. 提交事务前将事务信息清除
  8. 提交事务

5.spring 之事务步骤小结

  1. spring 容器初始化启动时,会去解析所有的配置文件,将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory
  2. 在事务 annotation-driven 标签的的解析过程中,会向 IOC 容器中注册四个 bean分别为:InfrastructureAdvisorAutoProxyCreator,TransactionAttributeSource,TransactionInterceptor,TransactionAttributeSourceAdvisor
  3. 同时,在 spring 容器初始化启动时,会完成向 IOC 容器中注册 bean 的工作。在注册的过程中,会去判断这些 bean 需不需要被代理(获取 bean 的事务或非事务增强器,有则需要代理,反之,不需要代理
  4. 如果不需要,则直接返回原始 bean,此时单例 bean 已完成向 IOC 容器的注册工作
  5. 如果需要,再确定代理方式是使用 JDK 代理,还是使用 Cglib,去创建代理对象 spring aop 代理对象的产生详情可以查看
  6. 当使用被代理对象调用被代理类的方法时,实际上是使用代理对象调用 invoke() 方法,也就是调用到了声明式的事务相关的处理(invokeWithinTransaction()方法是 spring 事务管理的核心)

6. spring 之事务理论小结

在应用系统调用声明 @Transactional 的目标方法或类时,spring 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据 @Transactional 的属性配置信息,由这个代理对象决定该声明 @Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用事务管理器PlatformTransactionManager 操作数据源 DataSource 提交或回滚事务

参考:https://blog.csdn.net/bskfnvjtlyzmv867/article/details/83960279

猜你喜欢

转载自blog.csdn.net/weixin_38192427/article/details/113620654