系列文章
spring 事务源码(三)如何保证被@Transactional标记方法中的所有sql都在一个事务内
前言
最近在研究事务的相关源码准备为项目中业务场景进行改造,写个博客记录,顺便分享如何查找调试源码的方法
准备调试代码
@Component
public class WebHelper {
@Transactional
public void test(){
System.out.println("test");
throw new RuntimeException("");
}
}
源码分析
首先看事务注解什么时候解析,并且注入切面
这里分享下我如何debug的方法,看看之前我的文章有个结论很关键,spring 切面都是基于动态代理模式,那么一定会生成代理对象,调用的方法应该都是
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
那么此时我只需要在这里打个断点
启动项目进入断点,在ida左侧debugger查看堆栈信息(忽略其他不重要信息)
createAopProxy:51, DefaultAopProxyFactory (org.springframework.aop.framework)
createAopProxy:105, ProxyCreatorSupport (org.springframework.aop.framework)
getProxy:110, ProxyFactory (org.springframework.aop.framework)
createProxy:473, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
wrapIfNecessary:355, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
postProcessAfterInitialization:304, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
applyBeanPostProcessorsAfterInitialization:431, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1703, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:573, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:495, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
......
这时候如果经常debugger的朋友看到这里就知道config
这个对象有个很关键的属性 advisors
这其实就是当前类所有切面,如果不知道也没关系,通过下面这种方式也能知道,看看这个代码之前的运行栈
来到wrapIfNecessary:355, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
看这英文也知道了,Create proxy if we have advice.
如果有切面增强创建代理类(advice 我猜测翻译过来是切面增强,不要在意这些细节)
那么这个specificInterceptors
就是当前对象所有切面了,从调试界面也能看到目前只有一个对象
org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
这时候我们在分析这个类
哪里将切面解析器注入
BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
那么哪里被注入呢
通过ida强大的引用分析功能能看到有ProxyTransactionManagementConfiguration
创建并在spring 中注入了这个对象
@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());
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() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
@Transactional事务注解何时解析
我们再回过头看看wrapIfNecessary:355, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
有个关键代码
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
然后一步一步往下看,我是在这里有点不确定是哪一行解析的,打断点重启
org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
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;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
同理最后来到
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// 方法匹配
MethodMatcher methodMatcher = pc.getMethodMatcher();
.....
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
......
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;
}
debugger往下走,到了
org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches
public boolean matches(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
这里结合上文BeanFactoryTransactionAttributeSourceAdvisor
类源码,这个TransactionAttributeSourcePointcut
是做为BeanFactoryTransactionAttributeSourceAdvisor#point
属性
这个方法中的tas
变量其实就是AnnotationTransactionAttributeSource
还是一样一点点debugger最终来到
SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
// 解析注解转为 TransactionAttribute
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
ae, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
}
// 注解属性转存
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<RollbackRuleAttribute> 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;
}
}
验证事务拦截器TransactionInterceptor
验证下事务是不是被这个类反射调用
只需要在事务注解方法中手动抛出异常打印下堆栈就知道了
下篇文章详细说说事务的具体调用