Spring事务源码:创建代理类
Posted jchen104
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring事务源码:创建代理类相关的知识,希望对你有一定的参考价值。
参考文章:
《Spring事务源码解析之tx:annotation-driven标签解析》
参考资料:
写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。
前言
本文我们介绍下Spring中的事务管理的源码,Spring的事务管理主要有申明式事务与编程式事务这两种,如果对这两种方式不了解的朋友可以先看下这篇文章(《Spring事务管理(详解+实例)》)然后再来深入源码分析。
我们通过如下方式开启事务,由于申明式事务的注入方式式基于代理方式实现的,因此这里也建议先了解下AOP的源码,这部分我前文已经做了完整的介绍,因此下文将不会对AOP的功能做深入的解析,有需要的朋友可以看下我之前AOP的文章。
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
目录
一、AnnotationDrivenBeanDefinitionParser
2、AnnotationDrivenBeanDefinitionParser
1.1、注册InfrastructureAdvisorAutoProxyCreator
1.2、设置proxy-target-class和expose-proxy属性
2.1、创建AnnotationTransactionAttributeSource
2.3、创建BeanFactoryTransactionAttributeSourceAdvisor
1、InfrastructureAdvisorAutoProxyCreator
2.3、computeTransactionAttribute
2.5、parseTransactionAnnotation
一、AnnotationDrivenBeanDefinitionParser
在介绍IOC时我们讲过Spring通过spring.handlers配置文件处理自定义命名空间节点(《Spring IOC:parseCustomElement调用链》),从下面的配置中可以看出TX标签由TxNamespaceHandler类解析。
http\\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
1、TxNamespaceHandler
TxNamespaceHandler中的init方法针对不通的属性配置实例化不通的解析对象,这里我们使用了annotation-driven,因此实例化的对象为AnnotationDrivenBeanDefinitionParser。
@Override
public void init()
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
2、AnnotationDrivenBeanDefinitionParser
下面就来到了AnnotationDrivenBeanDefinitionParser的parse方法,因为Spring事务管理也是基于创建代理类来实现的,因此和AOP一样首先需要创建代理创建器。
@Override
public BeanDefinition parse(Element element, ParserContext parserContext)
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
// 判断是否配置了mode属性且为aspectj,满足条件则走aop切面的方式管理事务
if ("aspectj".equals(mode))
registerTransactionAspect(element, parserContext);
else
// 默认方式,配置自动代理创建器
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
return null;
二、、AopAutoProxyConfigurer
创建代理创建器的流程可以拆解成如下几个步骤,我们下面分别对其进行分析。
private static class AopAutoProxyConfigurer
public static void configureAutoProxyCreator(Element element, ParserContext parserContext)
1、注册自动代理创建器
2、注册了事务管理器等Bean
1、注册自动代理创建器
configureAutoProxyCreator调用registerAutoProxyCreatorIfNecessary注册自动代理创建器
public static void configureAutoProxyCreator(Element element, ParserContext parserContext)
// 1、创建代理创建器
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
2、注册了AnnotationTransactionAttributeSource、TransactionInterceptor和BeanFactoryTransactionAttributeSourceAdvisor
registerAutoProxyCreatorIfNecessary分为三个步骤
(1)注册InfrastructureAdvisorAutoProxyCreator
(2)设置proxy-target-class和expose-proxy属性
(3)注册ComponentDefinition
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement)
// 向容器中注册InfrastructureAdvisorAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 设置proxy-target-class和expose-proxy配置
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册ComponentDefinition
registerComponentIfNecessary(beanDefinition, parserContext);
1.1、注册InfrastructureAdvisorAutoProxyCreator
很简单的方法,向容器中注册固定的BeanDefinition。
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source)
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
1.2、设置proxy-target-class和expose-proxy属性
解析标签中的proxy-target-class和expose-proxy属性值。proxy-target-class主要控制是使用Jdk代理还是Cglib代理实现,expose-proxy用于控制是否将生成的代理类的实例防御AopContext中,并且暴露给相关子类使用。
public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement)
if (sourceElement != null)
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass)
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy)
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
1.3、注册ComponentDefinition
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext)
if (beanDefinition != null)
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
2、注册了事务管理器等Bean
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
"org.springframework.transaction.config.internalTransactionAdvisor";
public static void configureAutoProxyCreator(Element element, ParserContext parserContext)
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
//1、注册自动代理创建器
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
// 判断容器中有无internalTransactionAdvisor
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName))
//2、注册了事务管理器等Bean
创建AnnotationTransactionAttributeSource
创建TransactionInterceptor
创建BeanFactoryTransactionAttributeSourceAdvisor
2.1、创建AnnotationTransactionAttributeSource
Object eleSource = parserContext.extractSource(element);
// 创建并注册AnnotationTransactionAttributeSource的BeanDefinition
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
2.2、创建TransactionInterceptor
这一步创建了TransactionInterceptor的BeanDefinition,并将上一步创建的AnnotationTransactionAttributeSource作为transactionAttributeSource属性注入了进去,这个属性后面创建代理类的时候将会用到。
另外调用了registerTransactionManager创建了事务管理器。
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);
registerTransactionManager创建了事务管理器,其实就是添加事务管理器的beanName。
private static void registerTransactionManager(Element element, BeanDefinition def)
def.getPropertyValues().add("transactionManagerBeanName",
TxNamespaceHandler.getTransactionManagerName(element));
事务管理器的beanName在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器。
// TxNamespaceHandler.java
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);
2.3、创建BeanFactoryTransactionAttributeSourceAdvisor
创建BeanFactoryTransactionAttributeSourceAdvisor的BeanDefinition,同时将前两个步骤中创建的AnnotationTransactionAttributeSource、TransactionInterceptor作为属性添加到当前Bean中,最后注册到容器中。
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order"))
dvisorDef.getPropertyValues().add("order", element.getAttribute("order"));
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
总结一下,这两部其实主要是注册了InfrastructureAdvisorAutoProxyCreator与BeanFactoryTransactionAttributeSourceAdvisor,可以从名字看出来一个是代理自动创建器,一个是增强器。
三、代理对象的创建
1、InfrastructureAdvisorAutoProxyCreator
InfrastructureAdvisorAutoProxyCreator类的继承关系如下图,可以发现其和我们之前介绍AOP时提到的AnnotationAwareAspectJAutoProxyCreator一样继承了AbstractAdvisorAutoProxyCreator。
抽象类AbstractAdvisorAutoProxyCreator继承了BeanPostProcessor接口,因此在Bean实例化的时候会去为其创建代理对象。这部分内容如果不熟悉可以看下我之前的文章(《Spring IOC:bean的生命周期与@Autowire(3)》、《Spring AOP源码2:查找增强器》)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
if (bean != null)
// 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 判断当前bean是否需要被代理,如果需要则进行封装(earlyProxyReferences中缓存的是已经创建好的代理对象)
if (!this.earlyProxyReferences.contains(cacheKey))
return wrapIfNecessary(bean, beanName, cacheKey);
return bean;
2、canapply
在创建代理类时,会先查找能够应用在当前bean上的增强器,这部分内容我们前文有过介绍就不赘述了,这里直接从如何判断是否适配的判断方法canapply来讲起。
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;
/* 判断当前增强是否可以应用在当前bean上 */
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
else
return true;
这里的advisor就是我们的增强器BeanFactoryTransactionAttributeSourceAdvisor,而pca.getPointcut()就是获取其内部创建的TransactionAttributeSourcePointcut。
@Override
public Pointcut getPointcut()
return this.pointcut;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut()
@Override
protected TransactionAttributeSource getTransactionAttributeSource()
return transactionAttributeSource;
;
该对象重写了getTransactionAttributeSource方法,获取的就是BeanFactoryTransactionAttributeSourceAdvisor在注册时添加的transactionAttributeSource属性,其实现类为AnnotationTransactionAttributeSource。
// configureAutoProxyCreator方法
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
继续往下深入,调用pc.getMethodMatcher()获取方法匹配器,这里的pc就是上文中的TransactionAttributeSourcePointcut类。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
Assert.notNull(pc, "Pointcut must not be null");
// 获取当前Advisor的CalssFilter,并且调用其matches()方法判断当前切点表达式是否与目标bean匹配,
// 这里ClassFilter指代的切点表达式主要是当前切面类上使用的@Aspect注解中所指代的切点表达式
if (!pc.getClassFilter().matches(targetClass))
return false;
// 判断如果当前Advisor所指代的方法的切点表达式如果是对任意方法都放行,则直接返回
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<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
// 遍历目标类上的接口方法
for (Class<?> clazz : classes)
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods)
// 使用matches判断能否作用于该方法上
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass))
return true;
return false;
2.1、getMethodMatcher
TransactionAttributeSourcePointcut的getMethodMatcher方法是在它的父类StaticMethodMatcherPointcut中实现的。
public final MethodMatcher getMethodMatcher()
return this;
该方法直接返回了this,也就是下面methodMatcher.matches方法就是调用TransactionAttributeSourcePointcut的matches方法。getTransactionAttributeSource即我们之前说过的AnnotationTransactionAttributeSource,getTransactionAttribute则是调用的其父类AbstractFallbackTransactionAttributeSource的方法。
public boolean matches(Method method, Class<?> targetClass)
if (TransactionalProxy.class.isAssignableFrom(targetClass))
return false;
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
2.2、getTransactionAttribute
getTransactionAttribute中判断有无缓存,如果缓存不存在则调用computeTransactionAttribute方法查找事务属性,获取后进行缓存。
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass)
if (method.getDeclaringClass() == Object.class)
return null;
// 先查询缓存
Object cacheKey = getCacheKey(method, targetClass);
Object cached = this.attributeCache.get(cacheKey);
if (cached != null)
if (cached == NULL_TRANSACTION_ATTRIBUTE)
return null;
else
return (TransactionAttribute) cached;
else
// 获取事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 事务属性不存在
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;
2.3、computeTransactionAttribute
computeTransactionAttribute方法会依次从方法上和类上查找事务申明,使用的是findTransactionAttribute方法。
这里注意下第一行的内容,只对public的方法可继续往下走,这就解释了为什么事务只在public方法上生效。
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass)
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers()))
return null;
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)
// 查看接口方法中是否存在事务声明
txAttr = findTransactionAttribute(method);
if (txAttr != null)
return txAttr;
// 查看接口类中是否存在事务声明
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method))
return txAttr;
return null;
2.4、findTransactionAttribute
findTransactionAttribute方法遍历所有的事务注解解析器,判断哪一个能用来进行解析,这里默认使用的是Spring的事务注解解析器SpringTransactionAnnotationParser。
protected TransactionAttribute findTransactionAttribute(Method method)
return determineTransactionAttribute(method);
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类初始化的时候初始化的
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly)
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
// 添加Spring事务注解解析器
this.annotationParsers.add(new SpringTransactionAnnotationParser());
// 添加JTA事务注解解析器
if (jta12Present)
this.annotationParsers.add(new JtaTransactionAnnotationParser());
// 添加EJB事务注解解析器
if (ejb3Present)
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
2.5、parseTransactionAnnotation
annotationParser.parseTransactionAnnotation调用了SpringTransactionAnnotationParser的parseTransactionAnnotation方法,内部又调用了parseTransactionAnnotation。
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae)
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null)
// 解析事务注解属性
return parseTransactionAnnotation(attributes);
else
return null;
parseTransactionAnnotation方法则解析了解析注解@Transactional注解中声明的各种属性。
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<RollbackRuleAttribute>();
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的增强,结合之前AOP的内容,整个步骤结束后会生成该Bean的代理类,在方法执行时调用的事务的生效正是由代理类来完成的,具体的事务控制我们将在下文讲解。
补充
事务仅对 public 方法有效
在本文内容的computeTransactionAttribute方法中,第一行在读取注解上的属性方法中,会优先判断方法是否是 public,如果不是 public,就不会读取事务配置信息。
因此@Transactional注解只能在public方法上生效。
如何知道使用的对象是spring的代理类
摘要:在项目中,涉及到同一个类中一个方法调用另外一个方法,并且两个方法的事务不相关,这里面涉及到一个事务切换的问题,一般的方法没问题,根据通过aop注解在方法上通过加注解标识,
答案是:通过spring aop类里面的AopContext类获取当前类的代理对象,
这样就能切换对应的事务管理器了,具体做法如下:
(1).在applicationContext.xml文件中配置如下:
[html] view plain copy
<!-- 开启暴露Aop代理到ThreadLocal支持 -->
<aop:aspectj-autoproxy expose-proxy="true"/>
(2).在需要切换的地方获取代理对象,再调用对应的方法,如下:
[java] view plain copy
((类名) AopContext.currentProxy()).方法();
(3).注意,这里需要被代理对象使用的方法必须是public类型的方法,不然获取不到代理对象,会报下面的错误:
[java] view plain copy
java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
开启暴露AOP代理即可.
因为开启事务和事务回滚,实际这个过程是aop代理帮忙完成的,当调用一个方法时,它会先检查时候有事务,有则开启事务,
当调用本类的方法是,它并没有将其视为proxy调用,而是方法的直接调用,所以也就没有检查该方法是否含有事务这个过程,
那么本地方法调用的事务也就无效了。 参考技术A 在application.yml中有以下配置
spring:
aop:
#auto: true #默认为true,可省略
proxy-target-class: true # 默认为false即JDK动态代理,我们一般要设为true,使用CGLIB代理
这种方式只能将代理模式修改为了CGLIG,但是不能设置暴露cglib代理的目标对象。
以上是关于Spring事务源码:创建代理类的主要内容,如果未能解决你的问题,请参考以下文章