这才是 Springboot 事务创建流程的正确打开方式

ProxyTransactionManagementConfiguration 这个类是一个普通的 Configuration 配置类,在加载它的过程中同样会扫描到它里面的 beanmethod 进行加载,这里面的几个也都比较重要,我们看看它的源码

@Configuration(proxyBeanMethods = false)``@Role(BeanDefinition.ROLE_INFRASTRUCTURE)``//会扫描它内部的beanMethod,进行加载,关于这beanmethod的所用,这里就不展看说了,具体在讲解到事务执行流程的时候再说吧``public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) //注意:这个方法的两个入参是后面两个beanmethod方法的bean对象 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 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) //这个类主要是过滤候选类是否可以被用来事务增强,并返回对应的事务属性对象 public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); }

@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; }

}

复制代码

到这里,我们看看主要加载的 bean 都有哪些

  • InfrastructureAdvisorAutoProxyCreator,BeanFactoryTransactionAttributeSourceAdvisor 主要是这两个 TransactionAttributeSource,TransactionInterceptor 这两个注入到了 BeanFactoryTransactionAttributeSourceAdvisor 这个对象中,就不单独说了,应该可以通过 BeanFactoryTransactionAttributeSourceAdvisor 这个 bean 对象获取到

2. InfrastructureAdvisorAutoProxyCreator 类

===========================================

我们看看 InfrastructureAdvisorAutoProxyCreator 的继承关系

这个类的继承关系是比较复杂的,我们只挑选我们最关注的来分析吧。

从图上可以看到 InfrastructureAdvisorAutoProxyCreator 类间接实现了 BeanPostProcessor 接口,这个接口主要的所用是对每一个 bean 对象初始化前后做增强。在每一个 bean 初始化前调用 postProcessBeforeInitialization,初始化后调用 postProcessAfterInitialization。

注意:这里说的 bean 初始化前后并不是创建对象前后,这些操作肯定都是在创建对象之后

3.BeanFactoryTransactionAttributeSourceAdvisor 类

================================================

我们现在看看 BeanFactoryTransactionAttributeSourceAdvisor 类,首先看下它的继承关系

可以看到这个类也实现了 Advisor 接口,这个接口主要是用来承载 Advice,而 Advice 主要是用来执行作为拦截器来使用的。

同时这个类也实现了 PointcutAdvisor,可以返回 Pointcut,可以用来筛选哪些方法需要拦截

4.判断 bean 对象是否需要进行事务增强处理

========================

bean 初始化后也会调用到 InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization 方法(在 AbstractAutoProxyCreator 这个类中)。继而会调用到 wrapIfNecessary 这个方法。我们去看看这个方法

//AbstractAutoProxyCreator类中的方法 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; }

// Create proxy if we have advice. //看上面的英文注释也能简单明白 aop就是在这里生成的,对应事务其实也是用aop来完成的,我们重点看看这里的代码。 //我们的@Transactional注解是在UserServiceImpl这个类上,所以我们就只关注这个类的执行过程就可以了,我们进到这个方法里面去看看 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //这个specificInterceptors主要是Advisor,这个不为空,说明当前的bean对象,可以被specificInterceptors来进行aop代理,就会进入里面的createProxy进行aop增强 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; }

复制代码

@Override``@Nullable``//这个方法主要是根据我们传入的bean,查找适用的advice和advisor,如果返回的是空,就说明不需要进行AOP增强,``protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray();``}

复制代码

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //这句比较简单,主要就是在beanFactory中获取类型是Advisor.class的对应bean,这个也比较简单,就跳进去看了, //我们这里会返回的List中就会只有org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); //这个主要是根据我们传入的bean对象,从candidateAdvisors返回合适的advisor,我们走进去看看 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors;``}

复制代码

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { //我们当前传入的BeanFactoryTransactionAttributeSourceAdvisor不是IntroductionAdvisor接口的实现,不会走到这里 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } //真正起所用的是在这里,我们继续跳进去看看 //canApply返回true,就说明当前的candidate能作用于当前clazz,就需要加到列表,后续生成aop代理的时候需要 if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }

复制代码

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 主要是通过getPointcut来获取Pointcut,从目标类上寻找应该被进行aop增强的类和方法 PointcutAdvisor pca = (PointcutAdvisor) advisor; //会走到这里面,我们继续进去看看,在这里就是去查找对应类的事务属性(简单来说就是获取方法上的@Transactional的相关属性),如果能获取到这里就会返回true,获取不到就会返回false`` return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; }``}

复制代码

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); //这个主要是判断类是否有必要pointcut的匹配。 //1. 如果类是TransactionalProxy、TransactionManager、PersistenceExceptionTranslator那就不需要后续匹配了直接从if分支里面返回 //2.或者要找的类是java.开头的,或者org.springframework.core这个接口,也从这里返回`` //我们当前查找的是事务的注解,名字是org.springframework.transaction.annotation.Transactional //我们当前要匹配的类是com.springboot.transaction.service.impl.UserServiceImpl //上面两个条件都不匹配,所以不会进入这个分支,继续向下走 if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; }

IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; }

Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { //会走到这里,将com.springboot.transaction.service.impl.UserServiceImpl加入到classes中 classes.add(ClassUtils.getUserClass(targetClass)); } //在这里会将当前类实现的接口com.springboot.transaction.service.UserService也加入进来 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); //在下面这里就会去遍历类上的所有方法,查找是否有 @Transactional注解 for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : //会走到下面这个匹配条件,我们进到这个方法去看看 methodMatcher.matches(method, targetClass)) { return true; } } }

return false; }

复制代码

//这个方法在TransactionAttributeSourcePointcut,这是一个抽象类``//当前这个类是BeanFactoryTransactionAttributeSourceAdvisor中的内部匿名类,类实例对象名是pointcut @Override public boolean matches(Method method, Class<?> targetClass) { //这个tas就是在初始化BeanFactoryTransactionAttributeSourceAdvisor这个bean时,注入上去的TransactionAttributeSource的bean TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }

复制代码

//这个方法在AbstractFallbackTransactionAttributeSource,``//注入上去的TransactionAttributeSource的bean的实际类型是AnnotationTransactionAttributeSource,它继承了AbstractFallbackTransactionAttributeSource``@Override``@Nullable``public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; }

// First, see if we have a cached value. //在这里会生成一个缓存的key Object cacheKey = getCacheKey(method, targetClass); //从缓存中查看对应的事务属性是否存在 ,如果存在就直接返回,我们这里是第一次,就会走到后面的获取部分 TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return cached; } } else { // We need to work it out. //在这就是在对应的method上去查看是否有对应Transactional注解,如果有,就封装成TransactionAttribute返回 //这个具体也是通过SpringTransactionAnnotationParser.parseTransactionAnnotation方法来完成的,这个比较简单,就不进去了 TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAttr == null) { //如果获取不到,为了避免后续重复查找,也会在这里添加缓存`` this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { //我们当前会走到这里,methodIdentification就是类名加方法名的拼接,作为描述 String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); if (txAttr instanceof DefaultTransactionAttribute) { DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr; dta.setDescriptor(methodIdentification); dta.resolveAttributeStrings(this.embeddedValueResolver); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } //在这里将解析出来的 TransactionAttribute添加到缓存中并返回 this.attributeCache.put(cacheKey, txAttr); } return txAttr; }``}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

学习分享,共勉

这里是小编拿到的学习资源,其中包括“中高级Java开发面试高频考点题笔记300道.pdf”和“Java核心知识体系笔记.pdf”文件分享,内容丰富,囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。同时还有Java进阶学习的知识笔记脑图(内含大量学习笔记)!

资料整理不易,读者朋友可以转发分享下!

Java核心知识体系笔记.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

中高级Java开发面试高频考点题笔记300道.pdf

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

架构进阶面试专题及架构学习笔记脑图

记一次蚂蚁金服Java研发岗的面试经历,分享下我的复习笔记面经

Java架构进阶学习视频分享

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值