0%

Spring事务的aop浅析

Spring事务的aop浅析

​ 结合之前说到的SpringAop浅析(二)本篇将从事务的角度,来看下spring或者说springboot是如何通过一些简单的配置就可以将一些方法进行事务的管理,并了解一些事务在管理过程中的一些简单api

浅析

​ 在没有spring之前,或者说在不引入spring的时候,在获取数据库访问的时候,通常是通过Connection来进行。通过Connection类来进行sql的执行操作,然后在sql执行完毕之后调用commit()方法,将事务提交,当然了,在借助spring框架之后,在编码过程中,再也没有通过这种方式来进行事务的提交。但是大差不差,这些事情是一定要做的,既然我们在编码过程中没有做,那么这件事情就一定被spring做了。

1
2
3
4
Connection conn = getConnection();
conn.setAutoCommit(false);
//执行一系列的sql
conn.commit();

​ 根据上篇文章springAop,不难猜测,spring肯定是借助于aop,对标记了@Transactional的方法进行拦截并进行事务的增强。那么它是怎么实现的呢?

spring中开启事务需要通过EnableTransactionManagement注解,实际上就是通过它来进行一些开箱即用的处理。这个注解的实现上引入了@Import注解,这个注解的作用是为了将某些类引入到Spring容器中。这样做有一个好处是,在启用这个注解的情况下,才引入某些类到容器中。

1
2
3
4
5
6
7
8
9
10
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

boolean proxyTargetClass() default false;

AdviceMode mode() default AdviceMode.PROXY;

int order() default Ordered.LOWEST_PRECEDENCE;

}

进入到TransactionManagementConfigurationSelector类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

/**
* 通过selectImports方法将某些类加载到容器中,这个方法返回一个字符串数组
* 这个字符串是类的全限定类名
*/
@Override
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;
}
}
}

重点来了,这里引入了两个类:

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

1.AutoProxyRegistar

它实现了ImportBeanDefinitionRegistrar接口。所以它的主要作用是将InfrastructureAdvisorAutoProxyCreator这个后置处理器类注入到容器中,那么容器在进行每一个bean对象初始化时都会将这个后置处理作用在对应的bean上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

private final Log logger = LogFactory.getLog(getClass());

/**
* 它的主要作用在AopConfigUtils.registerAutoProxyCreatorIfNecessary中,为了将org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
* 类注册到spring中,这个类实现了spring的后置处理器,主要作用是在spring的bean初始化的过程中,对bean进行检查,如果符合一定的条件
* 则把这个bean的aop代理对象注入到spring容器中。
*/
@Override
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) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
}

来看一下InfrastructureAdvisorAutoProxyCreator类。它自己本身没有什么太多的实现,它继承与AbstractAdvisorAutoProxyCreator抽象类,这个抽象类实现了一些查询那些增强可以作用在目标bean对象上处理。本篇想聊的后置处理的实现是在它的父类AbstractAutoProxyCreator上。

1
2
3
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
// ...省略代码
}

AbstractAutoProxyCreator中,实现了具体的后置处理的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 后置处理器实现
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
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;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// 在这里获取到需要的增强链,这里会获取到刚刚最早提到的,通过@EnableTransactionManagement
// 的import注解注入了两个类的第二个类,第二个配置类的作用是引入事务增强类。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
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;
}

1.ProxyTransactionManagementConfiguration

上面已经给出了结论,这个类的作用是引入了事务处理需要使用到的增强类。使得springBean对象在初始化时进入到后置处理器中,后置处理器再获取到这个类通过@Bean注解注入到容器中的增强类,从而实现将需要进行事务处理的类进行代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

/**
* 注入到容器中的事务增强类,它是Advisor接口的实现。它有两个参数,这两个参数也是通过容器来获取
* 也是在下方进行声明
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}

/**
* 上面增强类的第一个参数,这个bean的作用主要是用来获取事务属性的;比如配置的传播机制,异常信息等等;
* 这个bean当中提供了一个方法来获取
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}

/**
* 上面增强类的第二个参数,这个bean的作用主要是用来拦截,拦截目标方法之后进行事务的开启、提交、回滚等动作
*/
@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;
}
}

接下来看一下BeanFactoryTransactionAttributeSourceAdvisor类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

@Nullable
private TransactionAttributeSource transactionAttributeSource;

// 这里定义了切点的查找规则,也就是说bean进入了前面提到的后置处理器之后,会取出容器中的所有增强通知,然后逐个进行匹配
// 看遍历的到的通知是否需要作用到bean对象中,当遍历到这个增强时,就会通过TransactionAttributeSource类来进行匹配
// 也就是导入的配置类ProxyTransactionManagementConfiguration中定义的第二个bean对象
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
}

所以这里具体的匹配规则在类AnnotationTransactionAttributeSource中。

具体的匹配规则在它的父类AbstractFallbackTransactionAttributeSource#getTransactionAttribute()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// 计算是否匹配
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// ...省略代码,主要是推入缓存
return txAttr;
}
}

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// ..省略代码,主要是前置校验,是不是已经是代理类等等的操作

// 重点在这,通过这个方法获取到TransactionAttribute对象
// 这个方法的实现由AnnotationTransactionAttributeSource自己实现
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// ..省略代码

return null;
}

再回到AnnotationTransactionAttributeSource中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}

@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}

// 最终走到SpringTransactionAnnotationParser中,通过这个方法获取被@Transactional标记的方法或者类的信息
// 将@Transactional中定制化配置的信息读取到AnnotationAttributes对象中。
@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;
}
}

总结

spring事务的代理是通过@EnableTransactionManagement注解来开启,这个注解通过@Import注解来导入两个类,一个类是后置处理器,它的作用是在每个bean对象创建之后将第二个导入类中定义的增强作用在这个对象上,并形成代理对象。第二个导入类的作用是定义了一个增强,这个增强包含了如何确定切面、切点、连接点等信息,也包含了拦截的逻辑,也就是事务的开启、提交和回滚等处理。

-------------本文结束感谢您的阅读-------------