springboot事务回滚源码_002 | 搭上SpringBoot事务源码分析专车
发车啦,发车啦,上车要求:
点击左上方的“java进阶架构师”进入页面
选择右上角的“置顶公众号”上车
专车介绍
该趟专车是开往Spring Boot事务源码分析的专车
专车问题
为什么加上@Transactional注解就可以实现事务?
分析事务源码之后我们可以学到什么?
专车名词
事务
程序中通常使用事务来达到数据的一致性,从而避免脏数据
编程式事务
在业务方法开头开启事务,然后对我们的业务进行try-catch,假设没有异常则提交事务,如果出现异常,则在catch模块回滚事务
声明式事务由来
如果采用编程式事务,那么在任何需要事务的地方都要开启事务、try-catch、提交或者回滚事务,会导致重复编码、编写与业务无关的代码。基于Spring Aop思想,我们可以利用Aop的方式,对需要使用事务的方法进行增强,将公用的部分提取出来,那么就实现了声明式事务。
Spring提供的声明式事务
在需要使用事务的业务方法上添加@Transactional注解,那么就可以使用事务的特性,要么成功,要么失败
Spring Aop核心概念
切面:切面是由切点和通知组成
切点:用来匹配符合条件类或方法
通知:需要执行的操作
专车分析
基于Spring Boot自动配置原理,我们应该寻找xxxAutoConfiguration自动配置类,此处要寻找和事务相关的,那么自然是TransactionAutoConfiguration
自动配置
打开TransactionAutoConfiguration自动配置类
@Configuration@ConditionalOnBean(PlatformTransactionManager.class)@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)public static class EnableTransactionManagementConfiguration {
@Configuration@EnableTransactionManagement(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration@EnableTransactionManagement(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)public static class CglibAutoProxyConfiguration {
}
}
可以看到开启事务管理器的注解@EnableTransactionManagement
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement {}
查看TransactionManagementConfigurationSelector导入的类
protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {determineTransactionAspectClass()};default:return null; }}
可以看到导入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration
首先看看AutoProxyRegistrar,该类实现了ImportBeanDefinitionRegistrar
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) {// 注册自动代理创建器 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);return; } } } }}
注册自动代理创建器,AopConfigUtils#registerAutoProxyCreatorIfNecessary
public static BeanDefinition registerAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) {// 注册了InfrastructureAdvisorAutoProxyCreator到IOC容器中return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}
InfrastructureAdvisorAutoProxyCreator是AbstractAutoProxyCreator的子类,AbstractAutoProxyCreator又实现了BeanPostProcessor接口,那么在bean初始化完毕后就会调用postProcessAfterInstantiation()方法,postProcessAfterInstantiation()定义在AbstractAutoProxyCreator类中
BeanPostProcessor后置处理
打开AbstractAutoProxyCreator
@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {// 如果满足条件对bean进行包裹return wrapIfNecessary(bean, beanName, cacheKey); } }return bean;}
该方法调用了wrapIfNecessary()方法
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// Create proxy if we have advice.// 获取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;}
根据注释的意思就是如果存在advice,那么就创建代理,
寻找切面
进入AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean( Class> beanClass, String beanName, @Nullable TargetSource targetSource) {// 查找符合条件的切面 List advisors = findEligibleAdvisors(beanClass, beanName);// 不存在符合条件的切面,则不生成代理if (advisors.isEmpty()) {return DO_NOT_PROXY; }return advisors.toArray();}
该代码第一句最重要,如果不存在符合条件的切面,那么最终的结果返回null,根据上面分析的,如果为null就不创建代理,否则创建代理。接下来看看第一句的实现
protected ListfindEligibleAdvisors(Class> beanClass, String beanName) {// 获取所有候选的切面,也就是类型为Advisor的切面,此处获取到的候选切面为BeanFactoryTransactionAttributeSourceAdvisor List candidateAdvisors = findCandidateAdvisors();// 从候选的切面中获取可以解析当前bean的切面,最终符合条件的切面为BeanFactoryTransactionAttributeSourceAdvisor List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;}
为什么上面获取到的切面是BeanFactoryTransactionAttributeSourceAdvisor?是否还记得之前导入配置类的时候还有一个配置类没有分析?那就是ProxyTransactionManagementConfiguration
打开ProxyTransactionManagementConfiguration
@Configurationpublic class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 创建BeanFactoryTransactionAttributeSourceAdvisor@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.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; }}
通过上面的自动配置,可得知获取到的候选切面为什么是BeanFactoryTransactionAttributeSourceAdvisor
接下来看看如何从候选切面中找到可以解析当前bean的切面?
protected ListfindAdvisorsThatCanApply( List candidateAdvisors, Class> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);try {// 查找可以解析当前bean对应的切面return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); }finally { ProxyCreationContext.setCurrentProxiedBeanName(null); }}
查找可以解析当前bean对应的切面,AopUtils#findAdvisorsThatCanApply
public static ListfindAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors; } List 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 processedcontinue; }// 当前切面是否可以解析beanif (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } }return eligibleAdvisors;}
候选切面是否可以解析bean
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) {// 由上面分析知道最终的候选切面为BeanFactoryTransactionAttributeSourceAdvisor// 该类实现了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; }}
候选切面是否可以解析bean
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; }
// 获取切面切点方法匹配对象,用来匹配方法是否符合 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<>();if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));for (Class> clazz : classes) {// 通过反射获取当前类所有的Method对象 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;}
匹配方法TransactionAttributeSourcePointcut#matches
public boolean matches(Method method, Class> targetClass) {if (TransactionalProxy.class.isAssignableFrom(targetClass) || PlatformTransactionManager.class.isAssignableFrom(targetClass) || PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {return false; } TransactionAttributeSource tas = getTransactionAttributeSource();// 如果事务属性源对象为空或者事务属性对象不为null返回true,代表匹配成功;否则返回false,匹配失败return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);}
获取事务属性对象,AbstractFallbackTransactionAttributeSource#getTransactionAttribute
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class> targetClass) {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 {// 计算事务属性对象 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.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 = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.// 首先根据Method对象获取事务属性对象 TransactionAttribute txAttr = findTransactionAttribute(specificMethod);if (txAttr != null) {return txAttr; }
// Second try is the transaction attribute on the target class.// 如果根据Method对象获取不到事务属性对象,那么根据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;}
获取属性对象AnnotationTransactionAttributeSource#findTransactionAttribute
protected TransactionAttribute findTransactionAttribute(Class> clazz) {return determineTransactionAttribute(clazz);}
决定事务属性对象
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);if (attr != null) {return attr; } }return null;}
解析事务属性对象,SpringTransactionAnnotationParser#parseTransactionAnnotation
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {// 判断元素是否含有@Transactional注解,通过前面的分析我们可以得出如下结论:// 1、首选判断类的方法上是否含有@Transactional注解,如果有就解析// 2、如果所有的方法都不含有@Transactional注解,那么判断当前类是否含有@Transactional注解,如果有就解析// 3、如果类或者类的某个方法含有@Transactional注解,那么事务属性对象就不为空,则说明次切面可以解析当前bean AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false);if (attributes != null) {return parseTransactionAnnotation(attributes); }else {return null; }}
回到AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean; }if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean; }if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean; }
// Create proxy if we have advice.// 此处有值返回,进行代理,否则不进行代理 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;}
创建代理
创建代理AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); }
// 创建代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); }else { evaluateProxyInterfaces(beanClass, proxyFactory); } }
// 构建切面,此处的切面为BeanFactoryTransactionAttributeSourceAdvisor Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);// 设置切面 proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); }
return proxyFactory.getProxy(getProxyClassLoader());}
获取代理ProxyFactory#getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}
创建aop代理
protected final synchronized AopProxy createAopProxy() {if (!this.active) { activate(); }// 此处的this实际上就是ProxyFactoryreturn getAopProxyFactory().createAopProxy(this);}
aop代理工厂创建aop代理DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation."); }if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config); }// 创建cglib aop代理return new ObjenesisCglibAopProxy(config); }else {return new JdkDynamicAopProxy(config); }}
实例化ObjenesisCglibAopProxy对象
public ObjenesisCglibAopProxy(AdvisedSupport config) {super(config);}
父类实例化
public CglibAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified"); }// 此处的config就是之前的ProxyFactorythis.advised = config;this.advisedDispatcher = new AdvisedDispatcher(this.advised);}
回到之前获取代理的地方
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}
通过上面的分析可以得知createAopProxy()返回的是CglibAopProxy
通过CglibAopProxy获取代理,CglibAopProxy#getProxy
public Object getProxy(@Nullable ClassLoader classLoader) {if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); }
try { Class> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class> proxySuperClass = rootClass;if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class>[] additionalInterfaces = rootClass.getInterfaces();for (Class> additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface); } }
// Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...// 创建Enhancer对象 Enhancer enhancer = createEnhancer();if (classLoader != null) { enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } }// 设置父类 enhancer.setSuperclass(proxySuperClass);// 设置接口 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 获取回调,重点分析 Callback[] callbacks = getCallbacks(rootClass); Class>[] types = new Class>[callbacks.length];for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); }// fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));// 设置回调类型 enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.// 生成代理并创建代理实例return createProxyClassAndInstance(enhancer, callbacks); }catch (CodeGenerationException | IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +": Common causes of this problem include using a final class or a non-visible class", ex); }catch (Throwable ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex); }}
获取回调
private Callback[] getCallbacks(Class> rootClass) throws Exception {// Parameters used for optimization choices...boolean exposeProxy = this.advised.isExposeProxy();boolean isFrozen = this.advised.isFrozen();boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).// 实例化回调,在调用目标对象方法的时候执行 Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);return callbacks;}
实例化回调部分
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {// 设置切面信息,也就是之前的ProxyFactorythis.advised = advised; }
@Override@Nullable// 调用目标方法的时候执行public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null;boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource();try {if (this.advised.exposeProxy) {// Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; }// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = targetSource.getTarget(); Class> targetClass = (target != null ? target.getClass() : null);// 获取通知,此处的通知为TransactionInterceptor List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); }else {// We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal);return retVal; }finally {if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); }if (setProxyContext) {// Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }@Overridepublic boolean equals(Object other) {return (this == other || (other instanceof DynamicAdvisedInterceptor &&this.advised.equals(((DynamicAdvisedInterceptor) other).advised))); }/** * CGLIB uses this to drive proxy creation. */@Overridepublic int hashCode() {return this.advised.hashCode(); }}
调用invocation的处理方法,ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint(); }
// 此处的通知TransactionInterceptor Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {return dm.interceptor.invoke(this); }else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed(); } }else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.// 调用TransactionInterceptor#invokereturn ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}
调用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...// 以事务的方式进行调用return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}
事务方式调用
protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource();final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.// 创建事务信息对象 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.// 调用被代理对象方法 retVal = invocation.proceedWithInvocation(); }catch (Throwable ex) {// target invocation exception// 业务方法执行异常,进行事务回滚 completeTransactionAfterThrowing(txInfo, ex);throw ex; }finally {// 清除事务信息对象 cleanupTransactionInfo(txInfo); }// 提交事务 commitTransactionAfterReturning(txInfo);return retVal; }
else {final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);try {return invocation.proceedWithInvocation(); }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; } }}
到此事务的源码分析就结束了
专车总结
导入AutoProxyRegistrar、ProxyTransactionManagementConfiguration配置类
AutoProxyRegistrar用来注册InfrastructureAdvisorAutoProxyCreator到IOC中,InfrastructureAdvisorAutoProxyCreator实现了BeanPostProcessor
执行BeanPostProcessor的后置处理
获取由ProxyTransactionManagementConfiguration配置类创建的切面
通过切面解析bean是否需要创建代理,需要就创建代理
执行代理的回调,在回调中拿到通知
执行通知,通知里面逻辑:开启事务、执行目标方法、提交或回滚事务
专车回顾
回顾下开头的两个问题:
为什么加上@Transactional注解就可以实现事务?
分析事务源码之后我们可以学到什么?
通过以上分析,第一个问题应该就迎刃而解了,那么通过以上学到的知识我们可以实现什么功能呢?在下一篇我们会在此基础上进行实战,通过@SystemLog注解实现系统日志功能。感谢各位撸友乘坐此趟专车,欢迎下次继续乘坐
———— e n d ————
微服务、高并发、JVM调优、面试专栏等20大进阶架构师专题请关注公众号【Java进阶架构师】后在菜单栏查看。
看到这里,说明你喜欢本文
你的转发,是对我最大的鼓励!在看亦是支持↓
springboot事务回滚源码_002 | 搭上SpringBoot事务源码分析专车相关推荐
- 事务回滚什么意思 try_三问Spring事务:解决什么问题?如何解决?存在什么问题?...
1. 解决什么问题 让我们先从事务说起,"什么是事务?我们为什么需要事务?".事务是一组无法被分割的操作,要么所有操作全部成功,要么全部失败.我们在开发中需要通过事务将一些操作组成 ...
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
- 多个mapper的事务回滚_揭秘蚂蚁金服分布式事务 Seata 的AT、Saga和TCC模式
作者| 屹远(陈龙),蚂蚁金服分布式事务核心研发 . 导语 本文根据 8月11日 SOFA Meetup#3 广州站 <分布式事务 Seata 及其三种模式详解>主题分享整理,着重分享分布 ...
- springboot事务回滚源码_Spring Boot中的事务是如何实现的
1. 概述 一直在用SpringBoot中的@Transactional来做事务管理,但是很少想过SpringBoot是如何实现事务管理的,今天从源码入手,看看@Transactional是如何实现事 ...
- php try 并回滚,ThinkPHP异常处理、事务处理(事务回滚)
本篇文章给大家介绍,ThinkPHP异常处理.事务处理(事务回滚),用购买下订单减库存的案例分析,希望对大家在工作和学习中有所帮助. 1.Mysql建表引擎使用InnoDB,支持事务回滚. 2.代码案 ...
- 探坑mongoDB4.0事务回滚的辛酸历程
主管前几天发现mongoDB已经升级到4.0了,迫不及待得让我实现他期待已久的事务回滚,发现还是有很多坑啊! 下面是我将已有的本地mongoDB升级到支持事务回滚的历程,分享出来,有错误的地方欢迎指正 ...
- mysql事务 mysql事务回滚 MySQL事务死锁 如何解除死锁 资金出入账
这里写目录标题 问题 什么是事务 为什么需要事务 创建账户表 插入数据 无事务资金出入账 有事务资金出入账 事务死锁 死锁出现的原因 解决事务死锁 查看表级锁 查询表锁进程 查询行级锁 杀死行锁进程 ...
- JAVA事务回滚的使用方法
假设这是一个service类的片段 try{ //出现异常 } catch (Exception e) { e.printStackTrace(); ...
- Mysql事务回滚机制与原理
Mysql事务回滚机制与原理 文章目录 Mysql事务回滚机制与原理 一.事务回滚机制 二.使用到的技术讨论 三.redo log和undo log介绍 3.1 redo log 3.2 undo l ...
最新文章
- ECCV 2020 | PHOSA:一种基于单目图像的人-物重建方法
- 兰山天书(贺兰山岩画)
- fetch 自动加cookie_如何在shell中动态获取chrome浏览器的cookie信息
- Java中创建数组的几种方法
- maven详解之坐标与依赖
- 经纬度坐标系转东北天_大地坐标系(WGS-84)、地心地固坐标系(ECEF)与东北天坐标系(ENU)的相互转换C语言代码分享...
- 手机1像素线粗_关于移动端一像素线的解决方案
- python矩阵中插入矩阵_Python | 矩阵的痕迹
- 废旧手机屏幕做单片机显示屏_ipadmini显示屏拆解,一探究竟
- MySQL-(1)查看用户权限、(2)用户授权、(3)删除用户权限 语法格式总结
- EntityFramework 事务的使用
- 公钥、私钥和数字签名是什么
- 在窗体创建时显示窗体
- 自动控制原理第七版胡寿松pdf_自动控制原理简明笔记—(01)
- 撰写商业计划书的一些误区和建议
- 爱看小说网源码全站带数据打包ThinkPHP内核小说网站源码
- 他 1 个月写了个操作系统,退休后去做飞行员!
- POI 操作word
- Matlab中num2str函数的用法
- python基本常用语法函数数据结构
热门文章
- qtp连接mysql 无驱动_QTP连接MySQL
- 深度学习(二十九)——Normalization进阶, CTC
- python列表功能默写_Python list(列表)功能详解
- DWR的使用以及DWR中工具JS文件的使用
- Java集合-ArrayList源码解析-JDK1.8
- kudu 存储引擎简析
- 关于JSON.parse()方法的使用说明
- 基于bboss开发平台eclipse开发工程生成工具介绍
- InstallShield 2012 Spring新功能试用(17): Suite/Advanced UI 和 Advanced UI安装程序支持命令行Log参数...
- C# 遍历窗体控件顺序问题