zoukankan      html  css  js  c++  java
  • Spring事务源码

    启动事务

    @EnableTransactionManagement 注解来启用事务能力。

    参数解释
    proxyTargetClass:默认为false,表示使用 JDK 的代理模式,true表示用 CGLib 的代理模式,仅在 mode 是 PROXY 时才有效。
    mode:默认为PROXY,表示使用 AOP 代理来实现事务,ASPECTJ表示用 ASPECTJ 来实现事务,ASPECTJ 相比 PROXY 减少了一些使用限制,比如支持在同一个类内部方法调用。
    order:事务通知执行的顺序,默认优先级最低

    @Transactional 可以标注在类、接口、方法上,表示应用事务机制,

    参数解释
    value/transactionManager:如果有多个事务管理器时,指定一个事务管理器
    propagation:事务传播类型,默认 REQUIRED。还有 SUPPORTS/MANDATORY/REQUIRES_NEW/NOT_SUPPORTED/NEVER/NESTED
    isolation:事务隔离级别,默认为数据库的隔离级别,包括 READ_UNCOMMITTED/READ_COMMITTED/REPEATABLE_READ/SERIALIZABLE
    timeout:事务超时时间
    readOnly:是否只读,默认false
    rollbackFor:指定哪种类型的异常需要回滚
    rollbackForClassName:类似rollbackFor
    noRollbackFor:指定哪种类型的异常不需要回滚
    noRollbackForClassName:类似noRollbackFor

    事务传播类型说明

    枚举 描述
    REQUIRED 如果当前存在事务,方法会在该事务中运行,否则创建一个新事务。
    SUPPORTS 方法可以不需要事务,但是如果存在当前事务,则会在该事务中运行。
    MANDATORY 方法必须运行在事务中,如果当前事务不存在,则抛出异常。
    REQUIRES_NEW 方法必须运行在它自己的事务中,如果存在当前事务,该事务将被挂起。
    NOT_SUPPORTED 方法不应该运行在事务中,如果存在当前事务,该事务将被挂起。
    NEVER 方法不应该运行在事务中,如果存在当前事务,则抛出异常。
    NESTED 如果当前已经存在一个事物,方法会在嵌套事务中运行;如果不存在事务,其行为和 PROPAGATION_REQUIRED 一致。

    @EnableTransactionManagement 使用 @Import 导入 TransactionManagementConfigurationSelector,这个类继承了 AdviceModeImportSelector,也就是实现了 ImportSelector,所以配置类解析器会执行它的 selectImports() 方法,如下:

    protected String[] selectImports(AdviceMode adviceMode) {
    	switch (adviceMode) {
    		case PROXY:
    			return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
    		case ASPECTJ:
    			return new String[] {determineTransactionAspectClass()};
    		default:
    			return null;
    	}
    }
    

    这个方法根据通知模式 PROXY/ASPECTJ,选择导入不同的事务管理器。

    以默认方式 PROXY 为例,导入 ProxyTransactionManagementConfiguration 和 AutoProxyRegistrar。

    ProxyTransactionManagementConfiguration

    ProxyTransactionManagementConfiguration

    从它的继承关系可以看出,它是 @Configuration 配置类,并且实现了 ImportAware 接口,所以它会被注入 Spring 容器,此外,它还会通过 @Bean 注入下面这些组件:

    • AnnotationTransactionAttributeSource 解析 @Transactional 事务注解属性信息
    • TransactionInterceptor 保存事务注解的属性信息和事务管理器信息,它是实现 MethodInterceptor 的事务拦截器,所以会在目标方法执行时执行拦截。

    AutoProxyRegistrar

    AutoProxyRegistrar 是 ImportBeanDefinitionRegistrar 的实现类,所以 ConfigurationClassBeanDefinitionReader 会执行它的方法 registerBeanDefinitions(),并且在执行后置处理器时,会回调 ImportAware.setImportMetadata(),将 @EnableTransactionManagement 配置属性缓存至 AnnotationAttributes。

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    	boolean candidateFound = false;
    	Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
    	for (String annType : annTypes) {
    		AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
    		if (candidate == null) {
    			continue;
    		}
    		Object mode = candidate.get("mode");
    		Object proxyTargetClass = candidate.get("proxyTargetClass");
    		if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
    				Boolean.class == proxyTargetClass.getClass()) {
    			candidateFound = true;
    			if (mode == AdviceMode.PROXY) {
    			    // 注册 InfrastructureAdvisorAutoProxyCreator
    				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
    				if ((Boolean) proxyTargetClass) {
    				    // CGLib
    					AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    					return;
    				}
    			}
    		}
    	}
    }
    
    • 如果是 PROXY 类型的通知模式,注册 InfrastructureAdvisorAutoProxyCreator 到 BeanFactory;
    • 如果是 CGlib 代理,还要注册 AnnotationAwareAspectJAutoProxyCreator 到 BeanFactory;

    查看 InfrastructureAdvisorAutoProxyCreator 的继承关系,实际上和 AnnotationAwareAspectJAutoProxyCreator 是类似的,都继承 AbstractAdvisorAutoProxyCreator,可以回看 Spring AOP源码。也就是说,事务实际上就是利用 AOP 原理来实现的:通过 JDK/CGLib 动态代理技术,给需要事务增强的类创建增强后的代理对象,待代理方法执行时,利用代理对象来实现事务机制。

    执行代理对象

    Spring AOP源码 类似,只不过拦截器链中是 TransactionInterceptor,所以会执行其 invoke() 方法:

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
    
    	// 获取 @Transactional 注解事务属性
    	TransactionAttributeSource tas = getTransactionAttributeSource();
    	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    	// 如果没有指定,则按照类型获取事务管理器 PlatformTransactionManager
    	// 比如事务管理器 DataSourceTransactionManager
    	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    	// 获取需要执行的目标方法
    	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    
    	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    		// 将事务信息绑定到线程局部变量
    		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    
    		Object retVal;
    		try {
    			// 类似方法的环绕通知,会执行目标方法
    			retVal = invocation.proceedWithInvocation();
    		}
    		catch (Throwable ex) {
    			// 异常,使用事务管理器进行回滚
    			completeTransactionAfterThrowing(txInfo, ex);
    			throw ex;
    		}
    		finally {
    		    // 重置线程局部变量的事务信息
    			cleanupTransactionInfo(txInfo);
    		}
    		// 正常,使用事务管理器提交事务
    		commitTransactionAfterReturning(txInfo);
    		return retVal; // 方法返回
    	}
    }
    
  • 相关阅读:
    友盟上报 IOS
    UTF8编码
    Hill加密算法
    Base64编码
    Logistic Regression 算法向量化实现及心得
    152. Maximum Product Subarray(中等, 神奇的 swap)
    216. Combination Sum III(medium, backtrack, 本类问题做的最快的一次)
    77. Combinations(medium, backtrack, 重要, 弄了1小时)
    47. Permutations II(medium, backtrack, 重要, 条件较难思考)
    3.5 find() 判断是否存在某元素
  • 原文地址:https://www.cnblogs.com/bigshark/p/11324612.html
Copyright © 2011-2022 走看看