你必须懂也可以懂的Transactional原理

1.前言

系统应用开发过程中通常需要使用事务来保证业务数据的一致性,实现方式如:开启事务、执行数据库写操作、提交或者回滚事务,这种标准实现方式适用于少量一致性业务,如果存在大量需要保证数据一致性的业务,不仅会让开发人员重复编码,还会给系统造成冗余代码。基于这些问题,伟大的Spring框架为我们提供了@Transactional注解,那么它是如何使用一个注解就解决了我们的烦恼呢?我们该如何着手进行分析呢?

SpringBoot集成的功能往往要从一个xxxAutoConfiguration开始说起

2.自动配置

打开TransactionAutoConfiguration自动配置类可以看到一个比较重要的注解@EnableTransactionManagement用于开启事务管理功能,@EnableTransactionManagement注解又导入了AutoProxyRegistrarProxyTransactionManagementConfiguration

2.1 事务配置

ProxyTransactionManagementConfiguration中声明了一个切面BeanFactoryTransactionAttributeSourceAdvisor,看到切面必定会有相对应的切点TransactionAttributeSourcePointcut(用于声明切入的范围)和通知TransactionInterceptor(用于实现切入目标的后续操作)。

2.2 声明@Transactional注解处理器

1
2
3
4
5
java复制代码@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}

AnnotationTransactionAttributeSource实例化指定了注解解析器为SpringTransactionAnnotationParser

可以看到该解析器主要用来处理@Transactional注解

2.3 注入自动代理注册器

2.自动配置提到@EnableTransactionManagement还引入了AutoProxyRegistrar,向IOC容器中注入InfrastructureAdvisorAutoProxyCreator

1
2
3
4
5
java复制代码@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

InfrastructureAdvisorAutoProxyCreator实现了BeanPostProcessor接口,具有拦截并处理Bean的能力

2.3.1 Bean后置处理

1
2
3
4
5
6
7
8
9
10
java复制代码@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;
}

2.3.2 从容器中获取所有的Advisor

1
2
3
4
5
6
7
8
java复制代码/**
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}

2.3.3 筛选出符合条件的Advisor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// 1.获取切点对应的MethodMatcher
MethodMatcher methodMatcher = pc.getMethodMatcher();
for (Class<?> clazz : classes) {
// 2.获取当前类中的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 3.判断是否符合切点要求,此处的methodMatcher为TransactionAttributeSourcePointcut
if (methodMatcher.matches(method, targetClass)) {
return true;
}
}
}

return false;
}

判断方法上是否有@Transactional注解,如果有则使用SpringTransactionAnnotationParser进行解析并生成TransactionAttribute

2.3.4 Advisor排序

1
java复制代码sortAdvisors(eligibleAdvisors);

2.3.4 小结

1
2
3
4
5
6
7
8
9
10
11
12
java复制代码protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1.从容器中获取所有类型为Advisor的切面
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2.筛选出符合条件的切面(也就是类或方法上被@Transactional注解标注)
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 3.对符合条件的切面进行升序排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

2.4 选择代理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!IN_NATIVE_IMAGE &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
// 1.如果实现接口则选择jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 2.选择cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

2.4.1 生成代理

此处以cglib为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
Class<?> rootClass = this.advised.getTargetClass();
Class<?> proxySuperClass = rootClass;

// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

Callback[] callbacks = getCallbacks(rootClass);
}
}
1
2
3
4
java复制代码private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
}

创建Enhancer并指定回调为DynamicAdvisedInterceptor

2.5 调用代理

执行被代理对象目标方法userService.saveUser(user);时会调用DynamicAdvisedInterceptorintercept()方法

2.5.1 筛选满足条件的Advice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 1.遍历所有满足条件的Advisor,也就是2.3.3章节返回的Advisor
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 2. 判断是否满足切点要求
boolean match = mm.matches(method, actualClass);
// 3.满足切点要求
if (match) {
// 3. 获取切面对应的通知,也就是TransactionInterceptor
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 4.返回满足条件的通知
return interceptorList;
}

2.5.2 执行满足条件的Advice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码@Override
@Nullable
public Object proceed() throws Throwable {
// 1.如果没有advice可以执行,则执行目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}

// 2.从advice列表中取出一个advice
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 3.执行advice的invoke方法,也就是TransactionInterceptor的invoke
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
  1. 事务调用

3.1 获取事务配置属性

1
2
java复制代码TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

也就是@Transactional注解声明的属性

3.2 获取事务管理器

1
java复制代码final TransactionManager tm = determineTransactionManager(txAttr);

从容器中获取DataSourceTransactionManagerAutoConfiguration自动配置类中声明的事务管理器JdbcTransactionManager

1
2
3
4
5
6
7
8
9
10
java复制代码public class DataSourceTransactionManagerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionManager.class)
JdbcTransactionManager transactionManager(DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JdbcTransactionManager transactionManager = new JdbcTransactionManager(dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
}

3.3 执行事务

  1. 总结

@Transactional实现原理三要素切面切点通知

  • InfrastructureAdvisorAutoProxyCreator后置处理器拦截所有Bean
  • 遍历所有类型为Advisor切面
  • 返回满足切点条件的切面列表
  • 选择代理方法
  • 生成代理
  • 调用通知invoke()方法
    • 开启事务
    • 调用其它通知invoke()方法,如果没有执行目标方法
    • 执行异常,回滚事务
    • 执行成功,提交事务
  • 执行目标方法

了解@Transactional注解实现原理,不仅可以让我们对切面切点通知有一个清晰的认识,还可以让我们通过其思想实现类似功能,如@Cache注解实现应用缓存,@Async注解实现业务异步执行

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%