SpringBoot中的Transaction研究(四)Transactional


SpringBoot中的Transaction研究(一)TransactionManager
SpringBoot中的Transaction研究(二)PropagationBehavior
SpringBoot中的Transaction研究(三)TransactionInterceptor
SpringBoot中的Transaction研究(五)TransactionAttributeSource

本身对Transactional的处理应该是比较简单的,只需要把里面的值拷贝到TransactionAttribute即可,但是Spring作为框架考虑的更加全面,希望兼容更多,所以它定义了一套更加复杂的流程来处理这些兼容问题。我们可以通过这里对Transactional的处理来了解Spring框架是如何整合了一个又一个第三方的模块。

Spring Pattern

首先Spring需要自己定义一套标准,也就是Attribute接口,它提供了最大化的功能,然后创建一个Processor来将第三方的类转换为自己的标准。为了面对未知的各种可能,这里使用了IoC的技术,定了一个Parser接口,然后针对各个情况使用各自的实现类。Spring工程会负责在创建Processor的时候把能获取的Parser都添加给parsers列表。当processor需要process的时候就会逐个的调用parser来处理,这里processor有两种方法来调用parser,一种是parser实现一个boolean canParse() 方法来告诉processor是否调用自己的parse方法,另一种是processor直接调用Parser的parse方法,当parser发现自己无法处理的时候就返回null,这个时候processor就会调用下一个parser。这里使用的是后一种方法(如下图所示)。
在这里插入图片描述
由于各种第三方的功能不全,所以对于一些方法和属性需要一些默认值,即使这样还有的时候无法完全通过配置来实现,这个时候就需要对于一个方法有多种实现(例如下面的operation),那么这个时候就需要为各种情况创建相对应的Attribute,而不同的Parser返回的是各自的Attribute。那么类之间的关系就如下图所示
在这里插入图片描述
为了将第三方ForeignAnnotation处理成标准的SomeAttribute于是定义了ParserF,这个parser只会处理自己对应的annotation,对于其他则会返回null。对于SomeAttribute的各种getter可以定义DefaultAttribute来实现并且统一了默认值。但是对于复杂的情况例如operation1则还是需要各个Attribute分别来实现了。为了支持这些实现,可能各个Attribute还需要一个Field来存储一些信息。
总的来说每增加一种第三方的支持,就需要新增一个Parser(这个Parser需要在自己无法处理的时候return null),如果情况简单这里就是完成字段名的映射,将第三方的字段名映射为自己的字段名,把值设置到实体类即可。如果情况复杂则需要创建一个新类从而rewrite某些方法。

Implement

在了解了上面Spring的玩法后我们再来看看具体实现

Bean的创建

ProxyTransactionManagementConfiguration负责创建了和事务相关的各个Bean,其中transactionAttributeSource创建了我们想要的声明式事务的处理类。

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
//some code
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		//some code
	}

}

从这里也可以知道这世界上布置声明式事务这一种方法,TransactionAttributeSource有很多个实现类,在SpringBoot中的Transaction研究(五)TransactionAttributeSource中会介绍其他的情况

AnnotationTransactionAttributeSource

annotationParsers

这里并没有通过注入的形式获得TransactionAnnotationParser,而是自己通过硬编码设定了默认的实现类,代码如下

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {

	private static final boolean jta12Present;

	private static final boolean ejb3Present;

	static {
		ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
	}

	private final boolean publicMethodsOnly;

	private final Set<TransactionAnnotationParser> annotationParsers;


	/**
	 * Create a default AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 */
	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 * @param publicMethodsOnly whether to support public methods that carry
	 * the {@code Transactional} annotation only (typically for use
	 * with proxy-based AOP), or protected/private methods as well
	 * (typically used with AspectJ class weaving)
	 */
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		if (jta12Present || ejb3Present) {
			this.annotationParsers = new LinkedHashSet<>(4);
			this.annotationParsers.add(new SpringTransactionAnnotationParser());
			if (jta12Present) {
				this.annotationParsers.add(new JtaTransactionAnnotationParser());
			}
			if (ejb3Present) {
				this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
			}
		}
		else {
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}
	//some code
	}

findTransactionAttribute

@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
		return determineTransactionAttribute(clazz);
	}

	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		return determineTransactionAttribute(method);
	}

	/**
	 * Determine the transaction attribute for the given method or class.
	 * <p>This implementation delegates to configured
	 * {@link TransactionAnnotationParser TransactionAnnotationParsers}
	 * for parsing known annotations into Spring's metadata attribute class.
	 * Returns {@code null} if it's not transactional.
	 * <p>Can be overridden to support custom annotations that carry transaction metadata.
	 * @param element the annotated method or class
	 * @return the configured transaction attribute, or {@code null} if none was found
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		for (TransactionAnnotationParser parser : this.annotationParsers) {
			TransactionAttribute attr = parser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}

可以看到findTransactionAttribute进行了重载,那么 @Transactional 在Class上和Method上都是会生效的,如果都有呢?可以参见SpringBoot中的Transaction研究(五)TransactionAttributeSource中对于AbstractFallbackTransactionAttributeSource的分析

parseTransactionAnnotation

这里SpringTransactionAnnotationParserJtaTransactionAnnotationParser都将入参AnnotatedElement转化为AnnotationAttributes然后完成名字的映射,而Ejb3TransactionAnnotationParser的处理简单很多

SpringTransactionAnnotationParser

@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
		return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
	}

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		rbta.setQualifier(attributes.getString("value"));

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}

从上面可以看的出来当@Transactional同时设定了 rollback*noRollback* 的时候都会生效但是对于同一个Exception而言是*rollback**生效。

JtaTransactionAnnotationParser

这个和上面类似,只是方法名不同,分别是rollbackOndontRollbackOn,同样优先处理rollbackOn

@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
				element, javax.transaction.Transactional.class);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {
		return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
	}

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

		rbta.setPropagationBehaviorName(
				RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackOn")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("dontRollbackOn")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}

Ejb3TransactionAnnotationParser

它的不同点是对于rollback的处理并不是完全依赖配置的,所以它对于TransactionAttribute需要有自己的实现类从而rewrite

@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		javax.ejb.TransactionAttribute ann = element.getAnnotation(javax.ejb.TransactionAttribute.class);
		if (ann != null) {
			return parseTransactionAnnotation(ann);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(javax.ejb.TransactionAttribute ann) {
		return new Ejb3TransactionAttribute(ann.value());
	}

	/**
	 * EJB3-specific TransactionAttribute, implementing EJB3's rollback rules
	 * which are based on annotated exceptions.
	 */
	private static class Ejb3TransactionAttribute extends DefaultTransactionAttribute {

		public Ejb3TransactionAttribute(TransactionAttributeType type) {
			setPropagationBehaviorName(PREFIX_PROPAGATION + type.name());
		}

		@Override
		public boolean rollbackOn(Throwable ex) {
			ApplicationException ann = ex.getClass().getAnnotation(ApplicationException.class);
			return (ann != null ? ann.rollback() : super.rollbackOn(ex));
		}
	}

至此以及获取进行事务处理需要的所有信息,然后就是开始使用了,详情参见SpringBoot中的Transaction研究(三)TransactionInterceptor

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值