文章目录
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
这里SpringTransactionAnnotationParser和JtaTransactionAnnotationParser都将入参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
这个和上面类似,只是方法名不同,分别是rollbackOn和dontRollbackOn,同样优先处理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