Spring事务管理是基于Spring AOP的,我们在使用Spring事务管理时,需要在配置类上添加@EnableTransactionManagement注解,然后在业务类或方法上添加一个@Transactional注解,就可以开启一个事务,那么Spring是如果通过AOP来处理事务的呢?
一、加载配置类
@EnableTransactionManagement注解会加载TransactionManagementConfigurationSelector配置类,而该类实现了ImportSelector接口,所以在进行配置类解析时,会去调用该类的selectImports()方法,注册新的配置类
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
在@EnableTransactionManagement注解中,mode()的属性值为PROXY,所以,在selectImports()方法中又会去注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个配置类
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 默认是PROXY
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
// 表示不用动态代理技术,用ASPECTJ技术,比较麻烦了
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
}
1.1 注册AutoProxyCreator
AutoProxyRegistrar配置解析的时候,由于它实现了ImportBeanDefinitionRegistrar()接口,具有注册BeanDefinition的功能,在解析该类时,会调用registerBeanDefinitions()方法去注册一个InfrastructureAdvisorAutoProxyCreator类的BeanDefinition
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,才可以Bean进行AOP
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
// 设置InfrastructureAdvisorAutoProxyCreator的proxyTargetClass为true
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
InfrastructureAdvisorAutoProxyCreator同@Aspect中的AnnotationAwareAspectJAutoProxyCreator一样,都是一个BeanPostProcessor,在Bean实例初始化后中,会去判断当前Bean是否开启了事务,如果开启事务,生成一个代理对象
InfrastructureAdvisorAutoProxyCreator中的isEligibleAdvisorBean()方法用于判断一个Advisor是否是一个事务的Advisor,这一点在下面配置Advisor时会有体现
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
// 判断是不是一个合格的Advisor
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
1.2 配置Advisor
在ProxyTransactionManagementConfiguration配置类中,生成了三个Bean实例,主要就是去生成一个Advisor的Bean实例
1.2.1 生成Pointcut实例
AnnotationTransactionAttributeSource类就相当于是一个Pointcut,它的isCandidateClass()方法用于判断类上是否有@Transactional注解,但从它的名字可以看出,它并不是一个简单的Pointcut,它还包含了@Transcational注解定义的属性等
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// AnnotationTransactionAttributeSource中构造了一个SpringTransactionAnnotationParser,用来解析类或方法上的@Transactional注解
return new AnnotationTransactionAttributeSource();
}
public boolean isCandidateClass(Class<?> targetClass) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
1.2.2 生成Advise实例
TransactionInterceptor类相等于是一个Advice,在真正执行业务代码时,会调用它的invoke()方法,在invoke()方法里面才会真正去解决开启事务、事务传播级别、隔离级别等问题
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
1.2.3 生成Advisor实例
transactionAdvisor()方法其实就是去生成一个Advisor的实例,而一个Advisor包含了Advice和Pointcut两部分,会把上面生成的实例设置进来,然后生成一个Advisor实例
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// BeanFactoryTransactionAttributeSourceAdvisor内部定义了一个Pointcut,Pointcut在匹配时会用到transactionAttributeSource来解析类或方法上是否存在@Transactional
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
注:在生成这三个Bean实例时,都通过@Role注解指定了role值为2,与InfrastructureAdvisorAutoProxyCreator中的isEligibleAdvisorBean()方法相匹配
二、生成代理对象
如果开启了Spring事务的支持,也就是注册了InfrastructureAdvisorAutoProxyCreator类的实例,该类是一个BeanPostProcessor,所以在Bean实例初始化后的过程中,会去调用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization()方法,在《Spring AOP源码解析(下)》中,介绍了生成一个代理对象的整体逻辑,不同的只是Advisor,提供了不同的匹配逻辑,在上面配置Advisor时已经介绍了,Spring事务开始时,会注册一个BeanFactoryTransactionAttributeSourceAdvisor类型的Advisor,因为它实现了Advisor接口,所有在筛选的时候,这个Advisor会被拿出来,然后进行匹配,不同只是具体的匹配逻辑
// 找到所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 进行筛选
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
下面重点介绍BeanFactoryTransactionAttributeSourceAdvisor中的匹配逻辑
2.1 判断类是否匹配
因为BeanFactoryTransactionAttributeSourceAdvisor同样是实现了PointcutAdvisor接口,所以会进入到canApply()方法中,首先获取Pointcut对象
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
……
}
BeanFactoryTransactionAttributeSourceAdvisor中定义了一个TransactionAttributeSourcePointcut对象
其中TransactionAttributeSource对象是在配置Advisor时设置的,它实际是一个AnnotationTransactionAttributeSource类的实例
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
……
}
TransactionAttributeSourcePointcut类中定义类匹配的逻辑,就是生成Pointcut实例时提到的isCandidateClass()方法,该方法会判断当前类上是否有@Transactional注解
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
……
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}
2.2 判断方法是否匹配
如果类已经匹配了,还需要遍历类中的所有方法,根据方法来判断是否需要进行AOP
TransactionAttributeSourcePointcut中不仅定义了类的匹配逻辑,还定义了方法的匹配逻辑
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
……
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
……
}
遍历所有方法,调用matches()方法来进行匹配,而matches()方法中也是调用TransactionAttributeSource对象的getTransactionAttribute()方法来匹配,该方法返回的是一个TransactionAttribute对象,该对象里面是@Transcational注解的配置
调用getTransactionAttribute()时,先从缓存取,缓存没有再调用computeTransactionAttribute()方法来获取方法上@Transcational注解的值,如果返回的TransactionAttribute对象不为空,说明方法上有@Transcational注解,可以进行AOP
不论computeTransactionAttribute()方法返回的对象是否为空,都需要缓存一下,避免下次再次扫描
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// First, see if we have a cached value.
// 检查缓存里的结果,缓存里存了当前类和方法是否存在Transactional注解
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
……
}
else {
// We need to work it out.
// 解析,并缓存结果
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
dta.setDescriptor(methodIdentification);
dta.resolveAttributeStrings(this.embeddedValueResolver);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
computeTransactionAttribute()方法中,首先会去判断方法是不是public,也就是说,如果@Transcational定义的方法不是public方法,事务是没法生效的
接着调用findTransactionAttribute()方法去获取方法上@Transcational注解的属性配置
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 先检查方法上是否存在@Transactional
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 再检查类
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
……
return null;
}
在parseTransactionAnnotation()方法中,会去获取方法上@Transcational注解的属性值,如果没有注解属性,说明没有该注解
获取到注解的属性值后,通过parseTransactionAnnotation()方法来设置这些属性
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
@Transcational注解的属性值,包括了传播机制、隔离等级、超时、回滚、只读等参数
通过构建一个RuleBasedTransactionAttribute对象来保存@Transactional注解的参数,需要注意的是,rollbackRules这是一个回滚规则的列表,在@Transactional注解中,可以通过rollbackFor、noRollbackFor、rollbackForClassName、noRollbackForClassName来指定哪些异常和错误需要回滚或不会滚
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());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
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;
}
匹配之后,如果有符合条件的Advisor,就创建一个代理对象返回
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112146.html