一、前言
文章目录:Spring源码深度解析:文章目录
由于事务的源码和前篇的Aop源码逻辑很类似,所以本篇中某些内容不会展开去讲解,建议先阅读完全集目录中的Aop部分,再来阅读本文会更好理解。
二、@EnableTransactionManagement
我们在Springboot 中开始事务管理很简单,使用@EnableTransactionManagement
注解即可。
那么也就说明@EnableTransactionManagement
是我们分析的入口了。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
很明显了@Import(TransactionManagementConfigurationSelector.class)
指向我们去看
去看TransactionManagementConfigurationSelector
的实现。
三、TransactionManagementConfigurationSelector
可以看到,TransactionManagementConfigurationSelector
间接实现了ImportSelector
接口,这里简单提一下就是ImportSelector
会根据selectImports
返回的字符串数组(一般是类的全路径名) 通过反射加载该类并注册到Spring
容器中。
所以我们这里必然来看一下selectImports
方法了,ImportSelector #selectImports
的实现在其父类AdviceModeImportSelector#selectImports
ImportSelector# selectImports(AnnotationMetadata importingClassMetadata)
String[] selectImports(AnnotationMetadata importingClassMetadata);
AdviceModeImportSelector#selectImports(AnnotationMetadata importingClassMetadata)
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 获取注解类型, 这里是EnableTransactionManagement
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
// 解析出 @EnableTransactionManagement 注解的参数
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
// 获取mode属性。EnableTransactionManagement 默认mode = AdviceMode.PROXY
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
// 调用 TransactionManagementConfigurationSelector#selectImports
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
可以知道了 这里是将protected abstract String[] selectImports(AdviceMode adviceMode);
返回的值返回给 Spring
。这里我们看看在TransactionManagementConfigurationSelector
中的selectImports(AdviceMode adviceMode)
方法的实现。
AdviceModeImportSelector#selectImports(AdviceMode adviceMode)
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
TransactionManagementConfigurationSelector#selectImports(AdviceMode adviceMode)
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// 默认值是PROXY。个人猜测是通过 代理模式实现事务,如果是ASPECTJ则是通过ASPECTJ的方式实现,AspectJ需要单独引入编译
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
到这里就可以看到了,默认情况下,我们引入了两个类,AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
。
AutoProxyRegistrar
: 主要是注册了InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而InfrastructureAdvisorAutoProxyCreator
的逻辑基本上和Aop的逻辑相同ProxyTransactionManagementConfiguration
: 注册了事务实现的核心Bean
,包括BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor
等
本文讲述AutoProxyRegistrar
类的实现逻辑,关于ProxyTransactionManagementConfiguration
的内容新开了篇章:Spring源码深度解析:十八、事务实现② - ProxyTransactionManagementConfiguration
四、AutoProxyRegistrar
AutoProxyRegistrar
实现了ImportBeanDefinitionRegistrar
接口,所以我们要去看看他的registerBeanDefinitions
方法的实现。
AutoProxyRegistrar#registerBeanDefinitions()
代码如下:
@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;
}
// 获取mode、proxyTargetClass属性
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;
// 判断如果是Proxy模式,也就是默认模式,注册自动代理创建器
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 如果需要代理目标列,则强制自动代理创建者使用类代理
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isWarnEnabled()) {
String name = getClass().getSimpleName();
logger.warn(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
在这里我们可以看到,registerBeanDefinitions()
方法中解析了事务注解,并注册了自动代理创建器。这里自动代理创建器我们在Aop源码中提到过,是Aop创建的核心。
1. AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
这一步最主要的作用将自动代理创建器InfrastructureAdvisorAutoProxyCreator
注册到了 Spring
容器中。
经过数次跳转,我们来到了AopConfigUtils#registerOrEscalateApcAsRequired
。其中这
AopConfigUtils#registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry)
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
AopConfigUtils#registerAutoProxyCreatorIfNecessary
(BeanDefinitionRegistry registry, @Nullable Object source)
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
AopConfigUtils#registerOrEscalateApcAsRequired
(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source)
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
/**
* Stores the auto proxy creator classes in escalation order.
*/
// 保存候选的自动代理创建器集合。
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
// 这里面三种都是 自动代理创建器,会根据情况选择一个自动代理创建器加载。
// 需要注意的是,自动代理创建器只能加载一种,若已经加载一种,则会根据优先级选择优先级高的重新加载
// 事务使用
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// Spring AOP 使用
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
// 这里的 cls 是 AnnotationAwareAspectJAutoProxyCreator.class
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果有注册,则判断优先级,将优先级的高的保存
// 如果已经存在了自动代理创建器,且存在的自动代理创建器与现在的并不一致,那么需要根据优先级来判断到底要使用哪个
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
// 改变bean所对应的className 属性
apcDefinition.setBeanClassName(cls.getName());
}
}
// 如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再次创建
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
...
// 可以看到,所谓的优先级顺序实际上是在 APC_PRIORITY_LIST 集合的顺序
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 设置 proxyTargetClass 属性
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
...
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 设置 exposeProxy 属性
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
到这里我们基本可以断定和 Aop的逻辑基本相同了,只不过事务默认自动注入的自动代理创建器是 InfrastructureAdvisorAutoProxyCreator
类型。
注意:
- 在上篇Aop中我们知道 Aop创建的自动代理创建器类型是
AnnotationAwareAspectJAutoProxyCreator
,而事务创建的类型是InfrastructureAdvisorAutoProxyCreator
。 - 这里之所以
beanName (AUTO_PROXY_CREATOR_BEAN_NAME)
和bean
的类型并不相同,是因为这个beanName
特指内部的自动代理创建器,但是自动创建代理器会对应多种不同的实现方式。比如在默认的事务中,注入的bean类型却为InfrastructureAdvisorAutoProxyCreator
,而AOP的实现却是AnnotationAwareAspectJAutoProxyCreator
。 - 关于自动代理创建器优先级的问题,我们可以看到
APC_PRIORITY_LIST
集合的顺序,下标越大,优先级越高。因此可以得知优先级的顺序应该是
InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator
2. InfrastructureAdvisorAutoProxyCreator
上面我们可以知道,事务将自动代理创建器InfrastructureAdvisorAutoProxyCreator
注册到了Spring
容器中。这里就跟Aop
基本相同了,下面我们来看看InfrastructureAdvisorAutoProxyCreator
的内容
可以看到InfrastructureAdvisorAutoProxyCreator
并没有实现什么逻辑,主要逻辑在其父类 AbstractAutoProxyCreator
中。我们在Aop中提到过,AbstractAutoProxyCreator
是自动代理创建器的基础。绝大部分逻辑都是在其中实现的。(AbstractAutoProxyCreator
是AbstractAdvisorAutoProxyCreator
的父类,是 InfrastructureAdvisorAutoProxyCreator
的 "爷爷"类)。
@SuppressWarnings("serial")
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
// 校验bean是否合格
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
关于 AbstractAutoProxyCreator 的分析量十分巨大,这里不再重写分析一遍,详细内容可以去看 Aop分析文章的 Spring源码深度解析:十四、@Aspect方式的AOP上篇 - @EnableAspectJAutoProxy。
3. 事务中的 findCandidateAdvisors 方法
在这里,我们可以发现的是: Aop 的使用的是AnnotationAwareAspectJAutoProxyCreator
自动代理创建器;事务使用的是InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而Aop代理创建的关键逻辑就自动代理创建器中。
我们对比后两种自动代理创建器后,惊奇的发现,其现实逻辑基本一致。最大的不同之处在于,Aop 重写了AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
方法。而事务并没有重写这一部分。
所以事务调用的实际上是AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
。即下面一部分
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
而Spring aop调用的则是重写后的AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
可以清楚的看到,Aop 的重写是加了this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
方法调用,也就是动态生成
Advisor
的部分。
关于getAdvicesAndAdvisorsForBean
的源码分析可以看Spring源码深度解析:十五、@Aspect方式的AOP中篇 - getAdvicesAndAdvisorsForBean文章。其中的super.findCandidateAdvisors();
模块的分析
到这里我们知道了相较于Aop的 ,事务的InfrastructureAdvisorAutoProxyCreator
,不仅没有添加新逻辑(关键逻辑),还砍掉了动态生成Advisor
的逻辑。
Q: 为什么事务实现不需要动态生成Advisor 部分?
A:个人理解是因为由于事物的切入点并不像AOP那样如此多变。
- 何为Aop的切入点多变,即
Pointcut
的定义规则由代码掌握,我们通过@Pointcut
注解 可以定义一个匹配所有方法的切面,也可以定义一个匹配到指定的方法的切面,对于Spring
来说,Spring
无法通过一个Advisor
满足诸多Pointcut
条件,而为了满足这个条件所以需要通过代码来动态解析所有的Pointcut
来封装成一个一个的Advisor
,随后便可以通过Advisor
来判断该方法是否满足某个Advisor
的切入要求。 - 而对于事务来说,启用事务的方法必须要使用
@Transactional
来修饰方法(也可以修饰在类上,但这里为了方便描述直接说方法上,并且在类上使用更符合编程习惯)。也就是说对Spring来说,判断一个方法是否启用事务的依据就是该方法上是否使用了@Transactional
注解。也就是说,我们仅需要一个Advisor
,其判断条件是方法是否被@Transactional
注解修饰即可。而既然知道了Pointcut
条件,我们就可以实现编写好满足这个逻辑的 Advisor,在Spring启动时候直接将这个条件的Advisor
注入到容器中直接使用。 - 综上,事务并不需要去动态注入
Advisor
,而Spring aop
则需要动态注入。
通过上面的分析,我们判断,事务的Advisor
已经事先注入了,然后我们回头看到TransactionManagementConfigurationSelector
中注入的另一个类 ProxyTransactionManagementConfiguration
。在 ProxyTransactionManagementConfiguration
中果不其然发现了Advisor
的踪迹。
关于ProxyTransactionManagementConfiguration
的内容,请参看全集目录。
以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正