SpringIOC、AOP、事务源码流程粗记

AnnotationConfigApplicationContext

	public AnnotationConfigApplicationContext(String... basePackages) {
		this();
		scan(basePackages);
		refresh();
	}

this构造方法

1.初始化AnnotatedBeanDefinitionReader
2.初始化DefaultListableBeanFactory
3.注册一些后置处理器,例如ConfigurationClassPostProcessor

refresh方法

//1:准备刷新上下文环境
			prepareRefresh();

			//2:获取告诉子类初始化Bean工厂  不同工厂不同实现
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//3:对bean工厂进行填充属性
			prepareBeanFactory(beanFactory);

			try {
				// 第四:留个子类去实现该接口
				postProcessBeanFactory(beanFactory);

				// 调用我们的bean工厂的后置处理器. 1. 会在此将class扫描成beanDefinition  2.bean工厂的后置处理器调用
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册我们bean的后置处理器
				registerBeanPostProcessors(beanFactory);

				// 初始化国际化资源处理器.
				initMessageSource();

				// 创建事件多播器
				initApplicationEventMulticaster();

				// 这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
				onRefresh();

				//把我们的事件监听器注册到多播器上
				registerListeners();

				// 实例化我们剩余的单实例bean.
				finishBeanFactoryInitialization(beanFactory);

				// 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
				finishRefresh();
			}

prepareRefresh 设置容器id等
invokeBeanFactoryPostProcessors
根据PriorityOrdered、Ordered 排序后调用
BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor的方法
上文ConfigurationClassPostProcessor的就实现了这两个接口

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry

递归解析CompentScan、Import、@Bean、ImportSelector、ImportBeanDefinitionRegistrar
其中Import这三个注解都是实例化对象后反射调用,他们也实现了Aware接口

//实例化我们的SelectImport组件
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						//调用相关的aware方法
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
					
							//调用selector的selectImports
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							// 所以递归解析-- 直到成普通组件
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory

此方法主要是为Full的配置类BeanDefinition设置代理class

/*
			 只有full版配置类才会创建cglib代理
			 虽然我们在指定配置的时候不标注@Configuration也行,所以加不加注解的区别就在这里
			 那么加了@Configuration和不加有本质上有什么区别的?
			 当在配置类中一个@Bean 使用方法的方式引用另一个Bean如果不加注解就会重复加载Bean
			 如果加了@Configuration  则会在这里创建cglib代理,当调用@Bean方法时会先检测容器中是否存在*/
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
					if (configClass != enhancedClass) {
						if (logger.isDebugEnabled()) {
							logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +
									"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
						}
						// 重新修改Bean定义的Class,在创建Bean的实例时将会实例cglib的类
						beanDef.setBeanClass(enhancedClass);
					}

至此BeanDefinition解析完成

registerBeanPostProcessors
实例化我们的后置处理器,方便下面创建bean的时候生命周期调用

finishBeanFactoryInitialization 初始化剩下的单例bean

简单说一下过程
singletonsCurrentlyInCreation 集合是正在创建的bean的集合,创建完会移除,用来判断循环依赖
getBean->doGetBean->createBean->doCreateBean
1.先从一级缓存拿,没有从二级缓存拿,没有从三级缓存拿,实例化后放入二级缓存

所以 循环引用就是
A先放入三级,B放入三级,A放入二级,B放入一级,A放入一级

AOP

@EnableAspectJAutoProxy Import AspectJAutoProxyRegistrar
注册了AnnotationAwareAspectJAutoProxyCreator BeanDefinition
这个类的父接口 AbstractAutoProxyCreator 实现了 InstantiationAwareBeanPostProcessor
而InstantiationAwareBeanPostProcessor 接口会在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 之前调用

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		/**
		 * 获取容器中的所有后置处理器
		 */
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			//判断后置处理器是不是InstantiationAwareBeanPostProcessor
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				//把我们的BeanPostProcessor强制转为InstantiationAwareBeanPostProcessor
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				/**
				 * 【很重要】
				 * 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator
				 * 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator
				 * 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,
				 * 进行后置处理解析切面
				 */
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}
	
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
			int declarationOrderInAspect, String aspectName) {

		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

		// 获得当前通知的 切点表达式
		AspectJExpressionPointcut expressionPointcut = getPointcut(
				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
		if (expressionPointcut == null) {
			return null;
		}
		// 将切点表达式、 和通知  封装到InstantiationModelAwarePointcutAdvisorImpl对象中
		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
	}

也就是说加了这个注解,org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation 会在第一个bean 创建之前 解析Aspect @Before、@Pointcut这些注解,封装成beanname 和 Advisor的map,缓存起来,判断是否需要创建代理的时候用到

接下来就是创建代理

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

实现了

```java
org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)

判断是否需要代理
org.springframework.aop.aspectj.AspectJExpressionPointcut#matches(java.lang.Class<?>)

@Override
	public boolean matches(Class<?> targetClass) {
		PointcutExpression pointcutExpression = obtainPointcutExpression();
		try {
			try {
				return pointcutExpression.couldMatchJoinPointsInType(targetClass);
			}
			catch (ReflectionWorldException ex) {
				logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
				// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
				PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
				if (fallbackExpression != null) {
					return fallbackExpression.couldMatchJoinPointsInType(targetClass);
				}
			}
		}
		catch (Throwable ex) {
			logger.debug("PointcutExpression matching rejected target class", ex);
		}
		return false;
	}

利用Aspect能力粗筛、精筛
筛选到有Advisor 就去创建代理

注意一下三级缓存的这个接口

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference

他会调用

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference

而我们引用了切面的Enable注解上文不是会 实例 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference,他就实现了这个接口,所以他第一次创建的时候就会判断是否需要代理,如果代理了,放入earlyProxyReferences的Map,接下来 初始化就不会重复创建了

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			//获取缓存key
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 之前循环依赖创建的动态代理 如果是现在的bean 就不再创建,,并且移除
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 该方法将会返回动态代理实例
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

返回代理bean

	// 是早期对象暴露
		if (earlySingletonExposure) {
			/**
			 * 去缓存中获取到我们的对象 由于传递的allowEarlyReference 是false 要求只能在一级二级缓存中去获取
			 * 正常普通的bean(不存在循环依赖的bean) 创建的过程中,压根不会把三级缓存提升到二级缓存中
			 */
			Object earlySingletonReference = getSingleton(beanName, false);
			//能够获取到
			if (earlySingletonReference != null) {
				//经过后置处理的bean和早期的bean引用还相等的话(表示当前的bean没有被代理过)
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				}

而普通bean的创建是

@Override
	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

三级缓存为什么要使用工厂而不是直接使用引用?换而言之,为什么需要这个三级缓存,直接通过二级缓存暴露一个引用不行吗?

答:这个工厂的目的在于延迟对实例化阶段生成的对象的代理,只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会创建一个工厂并将其放入到三级缓存中,但是不会去通过这个工厂去真正创建对象
即使没有循环依赖,也会将其添加到三级缓存中,而且是不得不添加到三级缓存中,因为到目前为止Spring也不能确定这个Bean有没有跟别的Bean出现循环依赖。

假设我们在这里直接使用二级缓存的话,那么意味着所有的Bean在这一步都要完成AOP代理。这样做有必要吗?

不仅没有必要,而且违背了Spring在结合AOP跟Bean的生命周期的设计!Spring结合AOP跟Bean的生命周期本身就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。

EnableTransactionManagement

也是import了InfrastructureAdvisorAutoProxyCreator,他也是实现了org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
和我们aop 一样的实现接口
在这里插入图片描述
aop 事物都存在的时候 注册了相同的bean名称
在这里插入图片描述
但是只会保留一个,AOP的会覆盖事务的, 因为AOP优先级更大
所以事物注解的解析也是和aop 一样的,第一个bean 实例化的前置处理器

EnableTransactionManagement 还会import一个配置类,也就是我们需要的 BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor,以及父类的PlatformTransactionManager
aop 是自己扫描@Aspect构建出来的 advisor和advice、而事物是配置类配置的bean,这样事物的advisor 也会被扫描出来了

BeanFactoryTransactionAttributeSourceAdvisor 会设置TransactionAttributeSource
BeanFactoryTransactionAttributeSourceAdvisor中还会有TransactionAttributeSourcePointcut,
TransactionAttributeSourcePointcut 会有match方法,match方法就是调用TransactionAttributeSource的getTransactionAttribute方法,会在我们ioc 创建代理是调用

@Override
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
		/**
		 * 获取我们@EnableTransactionManagement注解为我们容器中导入的ProxyTransactionManagementConfiguration
         * 配置类中的TransactionAttributeSource对象
		 */
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 通过getTransactionAttribute看是否有@Transactional注解
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

上面说完了事物Advisor的构建和扫描,接下来说事物的代理创建
前面拿Advisor 和 aop 没区别,
从这开始有区别
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
aop是 粗筛->精筛
接下来我们看下 事物的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上面说了 事物配的TransactionAttributeSourcePointcut 是StaticMethodMatcherPointcut 子类,所以类过滤永远返回true,进不去,接着往下看
在这里插入图片描述
那么MethodMatcher就是我们上面设置的TransactionAttributeSourcePointcut ,看TransactionAttributeSourcePointcut的match方法就好,也就是
在这里插入图片描述
实现类方法—>接口的方法—>实现类---->接口类 这个去找没有@Transactional注解
org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
在这里插入图片描述
在这里插入图片描述
其实TransactionAttribute 也就是注解上的属性封装的对象,并放入缓存,TransactionAttribute属性解析不为空就是可以创建代理喽

调用事物代理

也就是我们配置类里配置的通知
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
org.springframework.transaction.interceptor.TransactionInterceptor#invoke
在这里插入图片描述

先看创建事物

也就是TransactionInfo对象
先说下主要结构
TransactionInfo里有TransactionStatus
DefaultTransactionStatus里有DataSourceTransactionObject
DataSourceTransactionObject 里有ConnectionHolder
而ConnectionHolder 保存了Connection 对象,如果ConnectionHolder有则基本说明存在事务
这里判断是否存在事务,
如果已存在就处理嵌套的事务逻辑, 这里我们待会作为分支再来跟进
如果不存在就处理顶层的事务逻辑,下面将先介绍顶层的事务逻辑
在这里插入图片描述
我们先看不存在就处理顶层的事务逻辑,那么就是开启一个事物,其实就是从数据源拿到一个Connection,并构建成ConnectionHolder,设置到DataSourceTransactionObject中,然后从TransactionAttribute给Connection设置一些是否只读,超时等,然后设置到现成变量里
resources 对象存放 ,key是数据源,value就说是ConnectionHolder对像,能拿到就说明存在嵌套事物
在这里插入图片描述

异常
在这里插入图片描述
rollbackOn属性不就是我们注解上的 很熟悉吧
没问题就提交
在这里插入图片描述
接下来细看获取事物的方法,里面涉及事物隔离级别

嵌套事物逻辑

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

其实就是对不同事物传播行为的判断处理
在这里插入图片描述
我们重点看下挂起怎么做的
其实就是清空线程变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
newTransaction:false, 代表不是一个新的事务,如果不是新事务,提交事务时: 由外层事务控制统一提交事务
org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值