Spring5源码15-事务(AutoProxyRegistrar和ProxyTransactionManagementConfiguration)
欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈
1. 案例(注解版)
- 引入依赖
build.gradle文件:
dependencies { api(project(":spring-context")) api(project(":spring-aspects")) //引入aop&切面模块 api(project(":spring-jdbc")) //引入jdbc模块 // https://mvnrepository.com/artifact/c3p0/c3p0 implementation group: 'c3p0', name: 'c3p0', version: '0.9.1.2' // https://mvnrepository.com/artifact/mysql/mysql-connector-java implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.18' // https://mvnrepository.com/artifact/org.projectlombok/lombok compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.14' }
- 注解版配置文件
@ComponentScan("com.hsf.spring.tx")
@Configuration
@EnableTransactionManagement
public class TxConfig {
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("hsfxuebao");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_tx");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception {
// Spring对@Configuration类会特殊处理,给容器中加组件的方法,多次调用都只是从容器中找组件
return new JdbcTemplate(dataSource());
}
// 注册事务管理器
@Bean
public PlatformTransactionManager transactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}
- 实例类
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO user(name,age) values(?,?)";
String name = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, name, 19);
}
}
@Service
public class UserInfoService {
public void test() {
System.out.println("UserInfoService.test()");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
// 不自动注入,模拟空指针异常
private UserInfoService userInfoService;
@Transactional()
public void insertUser() {
userDao.insert();
System.out.println("插入完成");
// 模拟空指针异常
userInfoService.test();
}
}
- 测试类
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(TxConfig.class);
// 事务
UserService userService = context.getBean(UserService.class);
userService.insertUser();
}
2. @EnableTransactionManagement
我们第1小节中开始事务管理很简单,使用 @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
的实现。
2.1 TransactionManagementConfigurationSelector
可以看到,TransactionManagementConfigurationSelector
间接实现了 ImportSelector
接口,ImportSelector
会根据 selectImports
返回的字符串数组(一般是类的全路径名) 通过反射加载该类并注册到Spring容器中
。
所以我们这里必然来看一下 selectImports
方法了,ImportSelector#selectImports
的实现在其父类AdviceModeImportSelector#selectImports
:
@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;
}
...
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
可以知道了 这里是将 protected abstract String[] selectImports(AdviceMode adviceMode);
返回的值返回给 Spring。这里我们看看在 TransactionManagementConfigurationSelector
中的 selectImports(AdviceMode adviceMode)
方法的实现。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@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[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
到这里就可以看到了,默认情况下,我们引入了两个类,AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
。
AutoProxyRegistrar
: 主要是注册了InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而InfrastructureAdvisorAutoProxyCreator
的逻辑基本上和 Aop 的逻辑相同ProxyTransactionManagementConfiguration
: 注册了事务实现的核心 Bean,包括BeanFactoryTransactionAttributeSourceAdvisor
、TransactionAttributeSource
、TransactionInterceptor
等
3. 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;
}
}
}
}
... 省略日志打印
}
在这里我们可以看到,registerBeanDefinitions
方法中解析了 事务注解
,并注册了自动代理创建器
。这里自动代理创建器我们在Aop 源码中提到过,是Aop 创建的核心。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
这一步最主要的作用将自动代理创建器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。
经过数次跳转,我们来到了 AopConfigUtils#registerOrEscalateApcAsRequired
。其中这
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
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);
}
....
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
...
// 这里的 cls 是 InfrastructureAdvisorAutoProxyCreator .class
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
3.1 InfrastructureAdvisorAutoProxyCreator
上面我们可以知道,事务将自动代理创建器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。这里就跟Aop 基本相同了,下面我们来看看 InfrastructureAdvisorAutoProxyCreator
的内容
可以看到 InfrastructureAdvisorAutoProxyCreator
并没有实现什么逻辑,主要逻辑在其父类 AbstractAutoProxyCreator
中。我们在Aop 中提到过, AbstractAutoProxyCreator
是自动代理创建器的基础。绝大部分逻辑都是在其中实现的。(AbstractAutoProxyCreator 是AbstractAdvisorAutoProxyCreator 的父类,是 InfrastructureAdvisorAutoProxyCreator 的 "爷爷"类)。
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分析文章的 AbstractAutoProxyCreator
部分。
3.2 事务中的 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
的源码分析可以看Spring5源码13-AOP源码分析(上)
到这里我们知道了 相较于 Aop 的 ,事务的 InfrastructureAdvisorAutoProxyCreator
,不仅没有添加新逻辑(关键逻辑),还砍掉了动态生成Advisor 的逻辑。
3.3 为什么事务实现不需要动态生成Advisor 部分?
个人理解是因为由于事物的切入点并不像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 的踪迹。
4. ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration
代码如下,并没有逻辑,就是将几个Bean注入的到容器中。不过这几个bean可都是关键bean,所以我们需要对其中的bean进行分析。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@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
@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;
}
}
BeanFactoryTransactionAttributeSourceAdvisor
: 事务的增强器,该方法是否开始事务,是否需要代理该类都在该类中判断
TransactionAttributeSource
: 保存了事务相关的一些信息资源。TransactionInterceptor
: 事务拦截器,事务生成代理类时使用的代理拦截器,编写了事务的规则
4.1 BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
这个根据上面的分析,我们可以知道这个是事务判断的核心,BeanFactoryTransactionAttributeSourceAdvisor
是Advisor
子类,那么我们可以知道其中有两个关键属性: Pointcut
(判断是否可以作用于当前方法) 和 Advice
(作用于当前方法的具体逻辑)。
通过 Aop文章的分析我们可以知道,Advisor
判断一个方法是否匹配,是通过其 Pointcut.matchs
属性来判断的。然后我们通过上面的代码,发现其 Pointcut
的实现类是 TransactionAttributeSourcePointcut
,也就是说,一个方法是否需要使用事务,是通过 TransactionAttributeSourcePointcut#matches
方法判断的。
4.1.1. TransactionAttributeSourcePointcut
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 调用 TransactionAttributeSource.getTransactionAttribute方法来匹配
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
... 省略一些无关代码
/**
* Obtain the underlying TransactionAttributeSource (may be {@code null}).
* To be implemented by subclasses.
*/
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
/**
* {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
* for filtering classes whose methods are not worth searching to begin with.
*/
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
// 如果是一些基础类,则返回false
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
PlatformTransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
// 调用 TransactionAttributeSource.isCandidateClass 方法来匹配
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}
Aop中我们总结了 Pointcut
匹配的需要满足下面两个条件:
pc.getClassFilter().matches(targetClass)
返回truepc.getMethodMatcher().matches(method, targetClass)
返回true
如下图,具体实现在 AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
中,这里第二点不考虑,因为在这里不会为True
通过 TransactionAttributeSourcePointcut
的代码我们可以发现,上面两个条件的关键
可以转换成
- 调用
TransactionAttributeSource.isCandidateClass
方法来匹配 :TransactionAttributeSourceClassFilter#matches
中调用了该方法 - 调用
TransactionAttributeSource.getTransactionAttribute
方法来匹配
而 TransactionAttributeSource
正是我们在 ProxyTransactionManagementConfiguration
中注入的 AnnotationTransactionAttributeSource
。
4.2 AnnotationTransactionAttributeSource
经过上面的分析,我们知道了主要逻辑在 isCandidateClass
和 getTransactionAttribute
方法中,也就是一个Bean 是否需要事务代理需要通过下面两个方法的校验。因此我们下面来看看这两个方法的实现
4.2.1 AnnotationTransactionAttributeSource#isCandidateClass
isCandidateClass
主要是 判断是否是候选类
,即当前的的注解解析器annotationParsers
是否可以解析当前类。annotationParsers
的初始化在其构造函数中,在初始化的过程中中添加了 SpringTransactionAnnotationParser
,我们后面的事务注解解析就是通过 SpringTransactionAnnotationParser
进行的解析。
这里annotationParsers 有三种解析类型:
SpringTransactionAnnotationParser
:即我们默认的事务解析器,解析的注解是org.springframework.transaction.annotation.Transactional
JtaTransactionAnnotationParser
:解析的注解是javax.transaction.Transactional
Ejb3TransactionAnnotationParser
:解析的注解是javax.ejb.TransactionAttribute
private final Set<TransactionAnnotationParser> annotationParsers;
...
public AnnotationTransactionAttributeSource() {
this(true);
}
...
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
// 可以看到,无论什么场景 SpringTransactionAnnotationParser 都是必定存在的解析器
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
@Override
public boolean isCandidateClass(Class<?> targetClass) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 这里是SpringTransactionAnnotationParser 类型, SpringTransactionAnnotationParser#isCandidateClass 中判断了目标类是否存在 org.springframework.transaction.annotation.Transactional 注解
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
在 SpringTransactionAnnotationParser#isCandidateClass
中判断了目标类是否存在 org.springframework.transaction.annotation.Transactional
注解,如果存在,这里会返回true,通过校验
4.2.2 AbstractFallbackTransactionAttributeSource#getTransactionAttribute
getTransactionAttribute
方法的实现在其父类AbstractFallbackTransactionAttributeSource
中 实现的:
// 获取事务属性,如果
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 判断声明类是否是 Object
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 尝试从缓冲中获取
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.
// 没有缓存,则开始解析
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
// 获取
if (txAttr == null) {
// 放入缓存中
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
// 获取合适的方法名称
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
...
// 解析事务注解属性
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
// 如果只允许解析public 方法 && 当前方法不是 publissh
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
// method 代表接口中的方法,specificMethod 方法代表实现类中的方法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 寻找实现类方法的事务属性,即类方法是否有声明事务属性
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 在实现类上是否有事务属性的声明
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 如果存在接口方法,则从接口方法中尝试去获取事务属性
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
// 都没得到则返回没有得到
return null;
}
这里的逻辑还是很清楚的
- 从实现类方法上获取事务注解,若获取到则返回
- 从实现类上获取事务注解,若获取到则返回
- 如果存在接口方法,则从接口方法中获取事务注解,若获取到则返回
- 若仍未获取到,则返回null,认为当前方法没有被注解修饰
AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
在上面的代码中,我们注意到一个方法 findTransactionAttribute
。上面代码就是通过 findTransactionAttribute
方法来寻找事务注解属性的。而findTransactionAttribute 的实现在 AnnotationTransactionAttributeSource
中。其实现代码如下
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
...
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
可以看到 AnnotationTransactionAttributeSource
中获取 事务注解是通过 TransactionAnnotationParser#parseTransactionAnnotation
方法去解析的,而一开始我们就说过annotationParsers
在构造函数中添加了SpringTransactionAnnotationParser
。我们来看看 SpringTransactionAnnotationParser
进行了怎么样的解析。到这里,我们终于看到了事务注解的描述,这里就是解析事务注解的各种属性信息了.
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 获取事务注解的属性信息
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
....
// 解析事务注解,并返回
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 解析各种属性信息
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
我们的分析到这里,就已经可以知道了Spring 中对事务注解的解析过程,逻辑基本和 Spring Aop 类似。
@EnableTransactionManagement
通过引入 TransactionManagementConfigurationSelector
注册了 AutoProxyRegistrar
和 ProxyTransactionManagementConfiguration
两个类。
AutoProxyRegistrar
中注册了 InfrastructureAdvisorAutoProxyCreator 自动代理创建器 InfrastructureAdvisorAutoProxyCreator 中拦截bean的创建过程,通过 BeanFactoryTransactionAttributeSourceAdvisor 来判断bean中是否有事务注解,有则进行代理。 在上面的逻辑中,我们似乎没有发现Spring事务代理的具体过程,实际上代理的过程是在TransactionInterceptor
中。
4.3 TransactionInterceptor
在 Aop 的分析文章中,我们知道了无论是 Jdk代理还是 Cglib代理,其增强实现都是调用 Advisor
中的Advice
实现。BeanFactoryTransactionAttributeSourceAdvisor
作为 Advisor 的实现类,自然要遵从 Advisor 的处理方式,当代理被调用时会调用这个类的增强方法,也就是此bean 的Advice ,而在解析事务标签是,我们把 TransactionInterceptor
注入到了 BeanFactoryTransactionAttributeSourceAdvisor
中,所以调用事务增强器增强代理类的时会首先执行TransactionInterceptor
进行增强,同时也就是 TransactionInterceptor#invoke
完成了整个事务的逻辑。
所以我们这里自然要看 TransactionInterceptor#invoke 方法。
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
// todo 在事务修饰下执行方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
可以看到核心逻辑都在 invokeWithinTransaction
方法中,这里调用的 invokeWithinTransaction
方法 实际是TransactionAspectSupport#invokeWithinTransaction
方法。所以下面我们来看看 TransactionAspectSupport#invokeWithinTransaction
方法的具体实现
TransactionAspectSupport#invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 获取事务数据源,这里获取的数据源就是在 TransactionInterceptor 注入的时候的设置的属性transactionAttributeSource = AnnotationTransactionAttributeSource。
// 在 ProxyTransactionManagementConfiguration 中完成
TransactionAttributeSource tas = getTransactionAttributeSource();
// 1. 获取对应的事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 2. 获取一个合适的 TransactionManager
final TransactionManager tm = determineTransactionManager(txAttr);
// 3. 对于反应式事务的处理
// 从Spring Framework 5.2 M2开始,Spring通过ReactiveTransactionManagerSPI 支持响应式/反应式事务管理
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
// 判断 tm是否是 PlatformTransactionManager 类型,是则强转,不是则抛出异常
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 构造方法的唯一标识( 全路径了类名.方法)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 4. 对不同事务情景的处理
// 声明式事务的处理
// 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强
// 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 5.如果有必要,创建事务信息。主要由于事务的传播属性,所以这里并不一定会创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 6. 执行被增强的方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 7. 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 8. 提交之前清除事务信息
cleanupTransactionInfo(txInfo);
}
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 9.提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式事务(CallbackPreferringPlatformTransactionManager)的处理。这里的逻辑基本都被封装了
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
try {
// 直接调用execute 方法。由于事务的提交回滚等操作都已经封装好了,所以这里并没有对事务进行详细的操作。
Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
// 准备事务信息
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
// 执行方法
Object retVal = invocation.proceedWithInvocation();
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
// 清除事务信息
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
从上面的代码中,我们可以知道Spring支持声明式事务和编程式事务
两种处理。两者的实现本质基本相同。在invoke方法中我们也可以看到这两种方式的实现,通常我们使用的都是通过 @Transactional
注解修饰的声明式事务,所以我们下面主要分析 声明式事务 的处理过程。
-
获取事务属性
TransactionAttribute
,TransactionAttribute
中包含 传播属性,timeout
等事务属性信息。如果是使用@Transactional
注解,这个解析过程是在AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
中完成。 -
加载配置中的
TrancationManager
, 事务管理器,是事务实现的基础,我们这里获取到的是DataSourceTransactionManager
。 -
对反应式事务的处理。
-
不同事务处理方式使用不同的逻辑。在上面的代码中主要是两种情况,一是声明式事务,这种情况是通过
@Transactional
注解修饰方法来表示开启事务。另一种情况是编程式事务,即可以通过xml方式或者配置类方式来进行完成事务功能,其实TransactionTemplate 的实现就是编程式事务,但通过TransactionTemplate
并不会走到这个逻辑,这里的编程式事务应该单独是通过xml或者配置类方式来配置的。- 对于声明式事务的处理和编程式事务的处理,区别主要在两点。一是事务属性上,因为编程式事务是不需要事务属性的,二是
TransactionManager
的不同,CallbackPreferringPlatformTransactionManager
实现了PlatformTransactionManager
接口,暴露了一个方法用于执行事务处理中的回调。所以这两种方式都可以作为事务处理方式的判断。
- 对于声明式事务的处理和编程式事务的处理,区别主要在两点。一是事务属性上,因为编程式事务是不需要事务属性的,二是
-
在目标方法执行前获取事务并收集事务信息。
- 事务信息与事务属性并不相同,也就是
TransactionInfo
和TransactionAttribute
并不相同,TransactionInfo
中包含TransactionAttribute
信息,并且处理TransactionAttribute
之外还有其他事物信息,比如PlatformTransactionManager
以及TransactionStatus
相关信息。
- 事务信息与事务属性并不相同,也就是
-
执行目标方法
-
如果出现异常,则进行回滚。这里需要注意,默认的情况下只有
RuntimeException
异常才会执行回滚。可以通过@Transactional(rollbackFor = Exception.class)
的方式来指定触发回滚的异常 -
提交事务前的事务信息清除
-
提交事务
-
若是 编程式事务,则直接执行execute方法即可,这里就不再讲解。
注:
PlatformTransactionManager
和ReactiveTransactionManager
二者都是为了实现事务,PlatformTransactionManager
在内部进行事务执行流程的封装,并且暴露出来一个execute
方法用于执行事务的具体信息,TransactionTemplate
的声明式事务就是基于此实现的。而ReactiveTransactionManager
则是比较原始的,需要我们自己来实现事务的整个逻辑。
上面比较笼统的讲了事务的实现,下面们主要分析以下三个方法,也是事务的的关键流程:
- 事务的创建 -
createTransactionIfNecessary
- 事务的回滚 -
completeTransactionAfterThrowing
- 事务的提交 -
commitTransactionAfterReturning
参考文章
Spring5源码注释github地址 Spring源码深度解析(第2版) spring源码解析 Spring源码深度解析笔记 Spring注解与源码分析 Spring注解驱动开发B站教程
转载自:https://juejin.cn/post/7143200472235507726