前言
@Transaction
是 Spring 声明式事务的使用方式。它让我们从复杂的事务处理中得到解脱,使我们再也不需要去处理获得连接、关闭连接、事务提交和事务回滚等操作,再也不需要在与事务相关的方法中处理大量的 try...catch...finally 代码。下面我们分别基于 Spring 和 基于 SpringBoot 两种方式,来了解其实现机制。
1. 基于 Spring
1.1 事务配置
在 Spring 中是基于 xml 文件配置的。
${jdbc.druid.url}
${jdbc.druid.user}
${jdbc.druid.filters}
${jdbc.druid.maxActive}
${jdbc.druid.initialSize}
${jdbc.druid.maxWait}
${jdbc.druid.minIdle}
${jdbc.druid.timeBetweenEvictionRunsMillis}
${jdbc.druid.minEvictableIdleTimeMillis}
${jdbc.druid.validationQuery}
${jdbc.druid.testWhileIdle}
${jdbc.druid.testOnBorrow}
${jdbc.druid.testOnReturn}
${jdbc.druid.poolPreparedStatements}
${jdbc.druid.maxOpenPreparedStatements}
1.2 事务标签解析
在 Spring 中,事务的开关是这个配置:
,于是,我们从这个配置开始分析。我们在 spring-tx 包下找到其 spring.handlers 文件:
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
"http://www.springframework.org/schema/tx" 这个自定义的命名空间处理器是org.springframework.transaction.config.TxNamespaceHandler
。于是我们直接跳到该类:
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
在这里,我们找到了我们想要的"AnnotationDrivenBeanDefinitionParser
,于是我们直接看其 parse 方法:
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
在解析中存在对于 mode 属性的判断,而其默认的 mode = "proxy"。
1.2.1 注册 InfrastructureAdvisorAutoProxyCreator
我们以默认配置为例子进行分析,进入AopAutoProxyConfigurer
类的 configureAutoProxyCreator
方法:
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 注册 InfrastructureAdvisorAutoProxyCreator
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// 创建 TransactionAttributeSource 的 bean
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 创建 TransactionInterceptor 的 bean
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 创建 TransactionAttributeSourceAdvisor 的 bean
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 将 TransactionAttributeSource 的 bean 注入 advisorDef 的 transactionAttributeSource 属性中
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
// 将 TransactionInterceptor 的 bean 注入 advisorDef 的 adviceBeanName 属性中
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
上面的代码注册了代理类InfrastructureAdvisorAutoProxyCreator
及 3 个 bean,其中的两个 bean (AnnotationTransactionAttributeSource
、TransactionInterceptor
) 被注册到了一个 bean 名为 advisorDef 的 bean 中,advisorDef 就是BeanFactoryTransactionAttributeSourceAdvisor
。
那么,我们不禁会问,注册代理类 InfrastructureAdvisorAutoProxyCreator
的 目的是什么呢?查看这个类的层次,如图所示:
从上面的层次结构中可以看到,
InfrastructureAdvisorAutoProxyCreator
实现了BeanPostProcessor
,也就是说在 Spring 中,所有 bean 初始化之后都会调用postProcessAfterInitialization
方法,其实现是在父类AbstractAutoProxyCreator
类中实现。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
// 构建一个缓存 key,一般为 beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 是否是由于避免循环依赖而创建的 bean 代理
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 对 bean 进行封装
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
这里实现的主要目的是对指定 bean 进行封装。我们看wrapIfNecessary
函数:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 不应该被代理的 bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 给定的 bean 类是否是一个基础类,如 Advice、Pointcut 等基础类型的类,或者配置了指定 bean 不需要自动代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果存在增强器,则创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
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;
}
该方法逻辑上理解起来还是相对简单的,主要的工作如下:
- 找出指定 bean 对应的增强器
- 根据找出的增强器创建代理
看起来似乎简单的逻辑,Spring 中又做了哪些复杂的工作呢?
1.2.2 获取对应 class/method 的增强器
获取指定 bean 对应的增强器。其中包含两个关键字:增强器与对应。也就是说在getAdvicesAndAdvisorsForBean
方法中,不但要找出增强器,而且还需要判断增强器是否满足要求。
protected Object[] getAdvicesAndAdvisorsForBean(Class> beanClass, String beanName, TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List findEligibleAdvisors(Class> beanClass, String beanName) {
List candidateAdvisors = findCandidateAdvisors();
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
第一步,寻找候选增强器findCandidateAdvisors
:
public List findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 获取 BeanFactory 中 Advisor 类型的 beanNames
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList();
}
List advisors = new LinkedList();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
// 判断是否存在循环依赖
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 实例化 Advisor 类型的 bean,并且放入 advisors 中
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
首先,通过BeanFactoryUtils
类提供的工具方法获取所有对应 Advisor 类型的 bean 名称,并且实例化这些 Advisor。或许你已经忘记了之前留下的悬念,在解析“BeanFactoryTransactionAttributeSourceAdvisor
的 bean。而在此 bean 中又注入了另外两个 bean,那么此时这个 bean 就会被使用了。因为BeanFactoryTransactionAttributeSourceAdvisor
同样实现了 Advisor 接口。那么在获取所有增强器时自然会将此 bean 提取出来,并在后续步骤中被织入代理。
第二步,候选增强器中找到匹配项findAdvisorsThatCanApply
:
当找出对应的增强器之后,接下来任务就是看这些增强器是否与对应 的 bean 匹配了。
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List eligibleAdvisors = new LinkedList();
//首先处理引介增强
for (Advisor candidate : candidateAdvisors) {
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;
}
// 对于普通 bean 的处理
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 pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
当前的 advisor 就是之前查找出来的BeanFactoryTransactionAttributeSourceAdvisor
类型的 bean 实例。而通过类层次结构,我们知道:BeanFactoryTransactionAttributeSourceAdvisor
间接实现了PointcutAdvisor
,因此会进入 canApply 函数中的第二个 if 判断。会将BeanFactoryTransactionAttributeSourceAdvisor
中的getPointcut()
方法的返回值作为参数继续调用 canApply 方法,而 getPointcut()
方法返回的是TransactionAttributeSourcePointcut
类型的实例。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
...
}
transactionAttributeSource
这个属性大家还有印象吗?这是在解析事务标签的时候注入进去的。
那么,使用TransactionAttributeSourcePointcut
类型的实例作为函数参数继续跟踪canApply
:
public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 此时的 pc 表示 TransactionAttributeSourcePointcut
// pc.getMethodMatcher() 返回的还是自身(this)
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> classes = new LinkedHashSet>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
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;
}
通过上面的函数大致可以理清大体脉络,首先获取对应类的所有接口并连同类自身一起遍历,遍历过程中又对类的方法再次遍历,一旦匹配成功便认为这个类适用于当前增强器。
做匹配的时候,methodMatcher.matches(method, targetClass)
会使用TransactionAttributeSourcePointcut#matches
方法:
public boolean matches(Method method, Class> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
// 获取 TransactionAttributeSource,事务标签解析时注入
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
此时的tas
表示AnnotationTransactionAttributeSource
类型,于是我们跟踪AnnotationTransactionAttributeSource#getTransactionAttribute
方法:
public TransactionAttribute getTransactionAttribute(Method method, Class> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
Object 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 (TransactionAttribute) cached;
}
}
else {
// 获取事务属性
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.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
该方法的作用是获取事务属性TransactionAttribute
,而具体的操作是在computeTransactionAttribute
方法中:
protected TransactionAttribute computeTransactionAttribute(Method method, Class> targetClass) {
// 必须是 public 方法,否则代理类无法调用该方法
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// Ignore CGLIB subclasses - introspect the actual user class.
Class> userClass = ClassUtils.getUserClass(targetClass);
// method 为接口中的方法,specificMethod 为实现类中的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// 处理桥生方法:父类是泛型,子类是具体类型而滋生的类型转换方法
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 查看方法是否存在事务声明
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 查看方法所在的类是否存在事务声明
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;
}
对于事务属性的获取规则相信大家都很清楚了。如果方法中存在事务声明,则使用方法上的事务属性,否则使用方法所在类上的事务属性;如果方法所在类上没有事务声明,则再搜索接口上的方法,再没有的话,最后搜索接口的类上的事务声明。
搜索事务声明的任务委托给了findTransactionAttribute
方法执行:
protected TransactionAttribute findTransactionAttribute(Class> clazz) {
return determineTransactionAttribute(clazz);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
if (ae.getAnnotations().length > 0) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
}
return null;
}
this.annotationParsers
是在当前类AnnotationTransactionAttributeSource
实例化的时候(构造函数)初始化的,其中加入了SpringTransactionAnnotationParser
,也就是当进行属性获取的时候其实是使用SpringTransactionAnnotationParser
类的parseTransactionAnnotation
方法进行解析的:
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
至此,我们终于看到了想要看到的获取事务注解标记的代码。首先会判断当前的类是否含有Transactional
注解,这是事务属性的基础。如果有的话,继续调用parseTransactionAnnotation
方法解析详细的属性:
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"));
ArrayList rollBackRules = new ArrayList();
Class>[] rbf = attributes.getClassArray("rollbackFor");
for (Class> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
上面的方法实现了对事务属性的解析,你会在这个方法中看到任何你常用的或者不常用的属性提取。
至此,我们终于完成事务标签的解析。我们是不是分析的太远了,似乎已经忘记了从哪里开始了。再回顾一下,我们现在的任务就是找出某个增强器是否适用于对应的类,而是否匹配的关键在于是否从指定的类或者类中的方法上找到对应的事务属性。
至此,事务的准备阶段已经完成。当判断某个 bean 适用于事务增强时,也就是适用于事务增强器BeanFactoryTransactionAttributeSourceAdvisor
,没错,还是这个类,所以说,在事务标签解析时,注入的类成为了整个事务功能的基础。
BeanFactoryTransactionAttributeSourceAdvisor
作为Advisor
的实现类,自然要遵循Advisor
的处理方式,当代理被调用时会调用这个类的增强方法,也就是此 bean 的Advice
,又因为在解析事务标签时我们把TransactionInterceptor
类型的 bean 注入到了BeanFactoryTransactionAttributeSourceAdvisor
的adviceBeanName
属性中。创建代理的时候,会调用Advisor#getAdvice
方法,此时就会得到的该增强方法TransactionInterceptor
,因为TransactionInterceptor
实现了Advice
,将其作为 CGLIB 的 CallBack 信息,@Transactional
修饰方法所在的类作为 CGLIB 的父类信息,CGLIB 根据这些信息生成对应的子类的 Class 对象作为代理类。所以,在调用事务增强器增强的代理类时,会首先执行TransactionInterceptor
进行增强,同时,也就是在TransactionInterceptor
类中的invoke
方法中完成了整个事务的逻辑。该部分逻辑我会单独拎出一篇文章来讲解。
2. 基于 SpringBoot
上面是基于 Spring 的事务标签"
2.1 事务配置
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "xxx.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class DataSourceConfig {
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource.xxx")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(Boolean.TRUE);
configuration.setUseGeneratedKeys(Boolean.TRUE);
sessionFactoryBean.setConfiguration(configuration);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:xxx.mapper/*.xml"));
return sessionFactoryBean.getObject();
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
在 SpringBoot 中,是通过@EnableTransactionManagement
注解,开启事务管理的,类似于 Spring 中的事务标签"
2.2 事务 @EnableTransactionManagement 注解解析
首先,看EnableTransactionManagement
注解的结构:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 是否需要使用 CGLIB
boolean proxyTargetClass() default false;
// 增强方式
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
这里使用了@Import
注解来引入配置类,相当于 Spring 中的"@Import
注解的参数可以是一个@Configuration
配置类,也可以是一个ImportSelector
接口,也可以是ImportBeanDefinitionRegistrar
接口的实现类。如果是一个 @Configuration
配置类,会将类中@Bean
修饰的 bean 注册到 IOC 容器;如果是ImportSelector
接口的实现类,那就会根据实现的逻辑对@Configuration
配置类或者ImportBeanDefinitionRegistrar
实现类进行筛选;如果是一个ImportBeanDefinitionRegistrar
接口实现类,那么也会根据该实现类的逻辑来创建 Bean。
2.2.1 TransactionManagementConfigurationSelector
于是我们继续跟踪TransactionManagementConfigurationSelector
:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
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;
}
}
}
TransactionManagementConfigurationSelector
是ImportSelector
接口的实现类,于是它会将selectImports
方法返回的配置类名数组,根据配置信息来创建指定的 bean。同样,我们以默认配置“adviceMode == PROXY”为例,进行分析。其会生成两个配置类AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
。
2.2.2 注册 InfrastructureAdvisorAutoProxyCreator
我们先看AutoProxyRegistrar
的结构:
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
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;
if (mode == AdviceMode.PROXY) {
// 注册 InfrastructureAdvisorAutoProxyCreator
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
...
}
AutoProxyRegistrar
实现了ImportBeanDefinitionRegistrar
接口,于是就可以在registerBeanDefinitions
方法中,注册自定义的 bean。注册了哪些 bean 呢?没错,你没看错,它注册的正是InfrastructureAdvisorAutoProxyCreator
,跟 Spring 解析事务标签时这注册的同一个 bean。我们知道,Spring 在解析事务标签时,除了注册InfrastructureAdvisorAutoProxyCreator
,还生成了三个 bean,分别是AnnotationTransactionAttributeSource
、TransactionInterceptor
以及BeanFactoryTransactionAttributeSourceAdvisor
。在AutoProxyRegistrar
并没有找到这些逻辑,于是我们猜测,应该在ProxyTransactionManagementConfiguration
中。
2.2.3 配置事务相关的 bean
我们继续跟踪ProxyTransactionManagementConfiguration
:
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
不出我们所料,ProxyTransactionManagementConfiguration
是一个典型的配置类,它创建了事务准备阶段所需要的3个 bean,AnnotationTransactionAttributeSource
、TransactionInterceptor
以及BeanFactoryTransactionAttributeSourceAdvisor
。并且前面两个 bean 都注入到了BeanFactoryTransactionAttributeSourceAdvisor
类型的 bean 中。
至此,@EnableTransactionManagement
注解,完成了和 Spring 中事务标签的解析工作所做的事情。后面 SpringBoot 继承了 Spring 的逻辑,依据这一个代理和 3 个 bean,找出指定 bean 对应的事务增强器,然后根据事务增强器创建代理,从而完成了事务的准备阶段。
3. 结语
本文分别基于 Spring 和 SpringBoot,介绍了@Transactional
注解在事务准备阶段所做的事情。
- 找出指定 bean 对应的事务增强器。
- 验证事务增强器与对应 bean 是否匹配(对应 bean 的类或者类中的方法上是否有事务属性)。
- 根据事务增强器创建代理。
创建代理之后,当程序调用事务方法时,就会走代理流程,下一篇文章我们将继续探讨。