首页 > 其他分享 >Spring事务

Spring事务

时间:2022-11-06 17:57:24浏览次数:51  
标签:事务 beanName return Spring Object bean 方法

传播特性

REQUIRED

当前方法存在事务时,子方法加入该事务。此时父子方法共用一个事务,无论父子方法哪个发生异常回滚,整个事务都回滚。即使父方法捕捉了异常,也是会回滚。而当前方法不存在事务时,子方法新建一个事务。

REQUIRES_NEW

无论当前方法是否存在事务,子方法都新建一个事务。此时父子方法的事务时独立的,它们都不会相互影响。但父方法需要注意子方法抛出的异常,避免因子方法抛出异常,而导致父方法回滚

NESTED

当前方法存在事务时,子方法加入在嵌套事务执行。当父方法事务回滚时,子方法事务也跟着回滚。当子方法事务发送回滚时,父事务是否回滚取决于是否捕捉了异常。如果捕捉了异常,那么就不回滚,否则回滚。

SUPPORTS

如果当前上下文中存在事务,那么加入该事务;否则用非事务方式执行

MANDATORY

当前方法必须要在有事务方法中运行,不然就抛出异常;如果有事务,就加入当前事务

NOT_SUPPORTED

如果当前上下文中存在事务,则挂起事务,新方法在没有事务的环境中执行

NEVER

当前方法不应该运行在事物中,如果有事务就抛出异常

源码

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
  /**
	 * 解析 <tx:annotation-driven/> 标签
	 */
	@Override
	@Nullable
  public BeanDefinition parse(Element element, ParserContext parserContext) {
		registerTransactionalEventListenerFactory(parserContext);
		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;
	}
  
  private static class AopAutoProxyConfigurer {

		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
      // 注册 InfrastructureAdvisorAutoProxyCreator
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
				Object eleSource = parserContext.extractSource(element);

				// 注册 AnnotationTransactionAttributeSource
        // 用来找 Transaction 注解
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				// 注册 TransactionInterceptor
        // 事务拦截器,执行方法时,开启事务/回滚事务/提交事务
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				// 注册 BeanFactoryTransactionAttributeSourceAdvisor
				// BeanFactoryTransactionAttributeSourceAdvisor 又是一个 PointcutAdvisor ,有一个切入点 TransactionAttributeSourcePointcut
				// TransactionAttributeSourcePointcut 用来匹配方法
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

				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);
			}
		}
	}
  
}

InfrastructureAdvisorAutoProxyCreator的祖父类AbstractAutoProxyCreator,实现了postProcessAfterInitialization方法,在 Bean 初始化后,会调用postProcessAfterInitialization方法用来创建代理对象

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
  public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			// cacheKey就是beanName或者beanClass
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 需要的话就使用动态代理产生代理对象
				// bean : 目标对象
				// beanName :目标对象名称
				// cacheKey:就是beanName或者beanClass
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
  
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 如果已经增强了,则不需要再生成代理了
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// isInfrastructureClass方法:Advice/Pointcut/Advisor/AopInfrastructureBean接口的beanClass不代理
		// shouldSkip方法:对beanName为.ORIGINAL结尾的bean不做代理
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 查找合适的Advisor(增强器)
    // 第一步:找到候选的Advisor,这里我们讲的是 Transactional,所以找到的是前面注册的 BeanFactoryTransactionAttributeSourceAdvisor
    // 第二步:找到合适的Advisor,BeanFactoryTransactionAttributeSourceAdvisor 又是一个 PointcutAdvisor ,有一个切入点 TransactionAttributeSourcePointcut ,通过 ClassFilter 和 MethodMatcher 来判断是否是合适 Advisor 。
    // 这里的 ClassFilter 是 ClassFilter.TRUE ,永远返回 TRUE 
    // 这里的 MethodMatcher 其实也是 TransactionAttributeSourcePointcut ,调用 matches 方法其实会调用之前注册的 AnnotationTransactionAttributeSource
    // 有兴趣的小伙伴可以跟一下源码
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

		// 对相应的advisor不为空才采取代理
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 通过jdk动态代理或者cglib动态代,产理生代理对象
			// 第三步:针对目标对象产生代理对象
			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;
	}

	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

    // 略。。。

		// 获取使用JDK动态代理或者cglib动态代理产生的对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}
}
public class ProxyFactory extends ProxyCreatorSupport {
  public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
}

createAopProxy()返回有CglibAopProxyJdkDynamicAopProxy,分别是 Cglib 代理和 JDK 动态代理。我们这里看 JDK 动态代理。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		// 获取完整的代理接口
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		// 调用JDK动态代理方法
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
}

JdkDynamicAopProxy也是一个InvocationHandler,当执行代理对象的方法时,就会执行JdkDynamicAopProxy#invoke方法。继续跟JdkDynamicAopProxy#invoke发现会拿到TransactionInterceptor,并执行invoke方法。我们主要看一下TransactionInterceptor#invoke方法

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
	
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
}

invokeWithinTransaction是父类的方法

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		TransactionAttributeSource tas = getTransactionAttributeSource();
    // 事务注解属性对象
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 事务管理器
		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;
		}

		else {
			// 略。。。
		}
	}
}

标签:事务,beanName,return,Spring,Object,bean,方法
From: https://www.cnblogs.com/back-garden/p/16863210.html

相关文章

  • GraalVM & Spring Boot初体验
    前言这两天封在家里,一直在琢磨想去把这个博客项目改成微服务的形式。不过就目前而言我的服务器内存放好几个Java进程是吃不消的,原因在于一个独立的JVM所占用的内存资源太......
  • Spring Security安全控制之快速入门
    在SpringCloud之服务注册中心搭建EurekaServer服务注册中⼼-池塘里洗澡的鸭子-博客园(cnblogs.com)中,一旦启动了Eureka服务器,就可以直接Eureka服务器管理界面—......
  • SpringBootJPA多表多条件查询(参数可能为空)语句
    @Query(value="SELECTc.bynameasbyname,c.cartascart,c.phoneasphone,c.surnameassurname,c.idasid,c.update_timeasupdateTime,c.head_imgasheadImg,c.i......
  • 使用idea将springboot打包成war包
    一、pom文件的配置:1.war打包方式设置为war。(不属于关键步骤)这里可以设置打包后的war包名。也是访问的时候的工程名。注:(打成war包访问的时候要加工程名),访问时如果忘记......
  • Springboot前后端分离项目部署到服务器上
    参考声明:https://www.cnblogs.com/thesheepn/p/16136425.html,感谢博主。1.安装JDK官网下载JDKhttps://www.oracle.com/java/technologies/downloads/#java8查看/usr/......
  • 如何将spring boot项目打包成war包
    声明:参考自https://www.cnblogs.com/kendoziyu/p/16085393.html一、修改打包形式在pom.xml里设置<packaging>war</packaging>二、移除嵌入式tomcat插件在pom.xml......
  • Spring Tx (六) (Spring事务失效的情况)
    文章目录​​1.访问权限问题​​​​2.方法被final修饰​​​​3.方法内部调用​​​​3.1.新增加一个service方法​​​​3.2.在该Service类中注入自己​​​​3.3.通过Aop......
  • Spring Tx (五) (分布式事务及解决方案)
    文章目录​​1.2PC​​​​1.1可能会存在哪些问题​​​​2.三阶段提交(3PC)​​​​3.补偿事务(TCC)​​​​3.1TCC解决了2PC的问题​​​​4.本地消息表​​​​5.消息事......
  • springboot整合项目-商城新增收货地址功能
    新增收货地址持久层1.新增规划sql语句insertintot_adress(字段列表)values(值列表)2.一个用户的收货地址规定最多只能由20条数据对应,在插入用户数据之前先做......
  • Spring Tx (七) (大事务问题)
    大事务引发的问题:死锁,锁等待,回滚时间长接口超时,数据库主从延迟,并发情况下数据库连接池被打满1.@Transactional注解是通过Spring的AOP起作用的,但是如果使用不当,事务......