事务传播机制
- REQUIRED (默认传播行为),支持当前事务,如果当前没有事务,就新建一个事务,这个当前事务指的是上一个方法的事务,是别人传递过去的,类似于重入锁,A方法和B方法都有事务,A方法调用B方法,A的事务会传递给B,使它们共用同一个事务,我起了个名字叫做重入事务
- SUPPORTS 如果存在一个事务,支持当前事务,如果没有事务,则非事务执行,
- REQUIRES_NEW 开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起
- MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
- NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务
- NEVER 总是非事务地执行,不加入任何事务;
- NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按 REQUIRED 属性执行。
TxNameSpaceHandler
XML中的tx:annotation-driven
注解用于开启事务,在TxNameSpaceHandler
中,进行自注册增强,springboot
是通过 @EnableTransactionManagement
进行注册和解析
NamespaceHandler(I) 解析xml自定义节点的 <--NamespaceHandlerSupport 提供注册BeanDefinitionParser和BeanDefinitionDecorator方法,用于解析节点 <--TxNamespaceHandler 解析tx:advice标签,用于解析事务相关
代码语言:java复制 //TxNameSpaceHandler
public void init() {
// springboot 使用 @EnableTransactionManagement
// 读取tx:advice ,调用父级的注册方法注册解析器
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
// 读取 xml 中 tx:annotation-dirvern 调用父级的注册方法注册解析器
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
/// 调用父级的注册方法注册解析器
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
AnnotationDrivenBeanDefinitionParser
解析 tx:annotation-dirvern <tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
/// 解析代理模式
String mode = element.getAttribute("mode");
/// <tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
if ("aspectj".equals(mode)) {
// mode="aspectj" 注册切面
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
AnnotationDrivenBeanDefinitionParser 中 aspectj 模式
代码语言:java复制 /**
* 注册切面
*/
private void registerTransactionAspect(Element element, ParserContext parserContext) {
// org.springframework.transaction.config.internalTransactionAspect
String txAspectBeanName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME;
// org.springframework.transaction.aspectj.AnnotationTransactionAspect
String txAspectClassName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_CLASS_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAspectBeanName)) {
RootBeanDefinition def = new RootBeanDefinition();
def.setBeanClassName(txAspectClassName);
def.setFactoryMethodName("aspectOf");
registerTransactionManager(element, def);
parserContext.registerBeanComponent(new BeanComponentDefinition(def, txAspectBeanName));
}
}
AnnotationTransactionAspect这玩意不是class,单独新增一个class还会报错。
代码语言:java复制public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
public AnnotationTransactionAspect() {
super(new AnnotationTransactionAttributeSource(false));
}
/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
* 查找所有带有@Transactional注解的或者子类中有的
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *) ).*(..)) && within(@Transactional *);
/**
* Matches the execution of any method with the Transactional annotation.
*/
private pointcut executionOfTransactionalMethod() :
execution(@Transactional * *(..));
/**
* Definition of pointcut from super aspect - matched join points
* will have Spring transaction management applied.
*/
protected pointcut transactionalMethodExecution(Object txObject) :
(executionOfAnyPublicMethodInAtTransactionalType() || executionOfTransactionalMethod() ) && this(txObject);
}
在看下AbstractTransactionAspect
代码语言:java复制public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport implements DisposableBean {
/**
* Construct the aspect using the given transaction metadata retrieval strategy.
* @param tas TransactionAttributeSource implementation, retrieving Spring
* transaction metadata for each joinpoint. Implement the subclass to pass in
* {@code null} if it is intended to be configured through Setter Injection.
*/
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}
@Override
public void destroy() {
/// 调用 TransactionAspectSupport#clearTransactionManagerCache
// An aspect is basically a singleton -> cleanup on destruction
clearTransactionManagerCache();
}
/// 这个就是 @around注解要干的事情了
@SuppressAjWarnings("adviceDidNotMatch")
Object around(final Object txObject): transactionalMethodExecution(txObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
try {
/// 调用 TransactionAspectSupport 里面的 invokeWithinTransaction
return invokeWithinTransaction(methodSignature.getMethod(), txObject.getClass(), new InvocationCallback() {
public Object proceedWithInvocation() throws Throwable {
return proceed(txObject);
}
});
}
catch (RuntimeException | Error ex) {
throw ex;
}
catch (Throwable thr) {
Rethrower.rethrow(thr);
throw new IllegalStateException("Should never get here", thr);
}
}
/**
* Concrete subaspects must implement this pointcut, to identify
* transactional methods. For each selected joinpoint, TransactionMetadata
* will be retrieved using Spring's TransactionAttributeSource interface.
*/
protected abstract pointcut transactionalMethodExecution(Object txObject);
/**
* Ugly but safe workaround: We need to be able to propagate checked exceptions,
* despite AspectJ around advice supporting specifically declared exceptions only.
*/
private static class Rethrower {
public static void rethrow(final Throwable exception) {
class CheckedExceptionRethrower<T extends Throwable> {
@SuppressWarnings("unchecked")
private void rethrow(Throwable exception) throws T {
throw (T) exception;
}
}
new CheckedExceptionRethrower<RuntimeException>().rethrow(exception);
}
}
}
AnnotationDrivenBeanDefinitionParser 中 proxy 模式
AopAutoProxyConfigurer.configureAutoProxyCreator(element,parserContext); ,看下这个方法
代码语言:java复制/*
* 此方法主要作用是注册四个类到容器中
* AnnotationTransactionAttributeSource 用于读取 @Transactional
* TransactionInterceptor 切面aspect
* BeanFactoryTransactionAttributeSourceAdvisor advisor
* InfrastructureAdvisorAutoProxyCreator 用于创建代理对象
*/
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 向IOC注册 registerAutoProxyCreatorIfNecessary 这个类型的Bean InfrastructureAdvisorAutoProxyCreator
// 具体是在 AopConfigUtils 的 registerAutoProxyCreatorIfNecessary 方法中定义的 registerAutoProxyCreatorIfNecessary
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
// org.springframework.transaction.config.internalTransactionAdvisor
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// Create the TransactionAttributeSource definition.
/// 注册 TransactionAttributeSource
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// Create the TransactionInterceptor definition.
// 注册TransactionInterceptor
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
// 注入 AnnotationTransactionAttributeSource
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// Create the TransactionAttributeSourceAdvisor definition.
// 注册 TransactionAttributeSourceAdvisor
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注入AnnotationTransactionAttributeSource,提供pointcut,切点
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
// 注入TransactionInterceptor 的beanname
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
// 注册BeanFactoryTransactionAttributeSourceAdvisor BeanDefinition
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
// 构建CompositeComponentDefinition完成以上Bean注册
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
实现了 BeanPostProcessor
,关注一下它的两个方法:postProcessBeforeInstantiation
和postProcessAfterInitialization
// AbstractAutoProxyCreator#postProcessAfterInitialization
/**
* 创建代理
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
/// 生成一个key 如果beanName不为空,则为 & beanName,否则为 bean的Class
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// AbstractAutoProxyCreator#wrapIfNecessary
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
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;
}
// 给定的bean类是否是一个基础设施类,基础设施类不应该被代理,或者配置了指定的bean不需要代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
* TransactionInterceptor 切面aspect
/// 先查找 Advisor 主要包括两种 IntroductionAdvisor 和 PointcutAdvisor,这里会将前面注入的 BeanFactoryTransactionAttributeSourceAdvisor 返回
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;
}
看下 getAdvicesAndAdvisorsForBean
调用过程
/**
* AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
*/
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
/**
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
* AbstractAdvisorAutoProxyCreator#
* 获取所有符合条件的Advisor用于后续自动代理使用,会返回 BeanFactoryTransactionAttributeSourceAdvisor
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
/**
* AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
* Search the given candidate Advisors to find all Advisors that
* can apply to the specified bean.
* @param candidateAdvisors the candidate Advisors
* @param beanClass the target's bean class
* @param beanName the target's bean name
* @return the List of applicable Advisors
* @see ProxyCreationContext#getCurrentProxiedBeanName()
*/
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
跟踪一下 this.advisorRetrievalHelper.findAdvisorBeans();
和 AopUtils.findAdvisorsThatCanApply
/**
* BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
/// 查找所有的 Advisor Bean
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" name "'");
}
}
else {
try {
/// 进行实例化
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("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;
}
代码语言:java复制/**
* Determine the sublist of the {@code candidateAdvisors} list
* that is applicable to the given class.
* @param candidateAdvisors the Advisors to evaluate
* @param clazz the target class
* @return sublist of Advisors that can apply to an object of the given class
* (may be the incoming List as-is)
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// IntroductionAdvisor 用于增加类方法,创建代理对象后,代理对象实现新的接口方法,进行判断
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;
}
/**
* Can the given pointcut apply at all on the given class?
* <p>This is an important test as it can be used to optimize
* out a pointcut for a class.
* @param pc the static or dynamic pointcut to check
* @param targetClass the class to test
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Pointcut pc, Class<?> targetClass) {
return canApply(pc, targetClass, false);
}
/**
* 这里会调用 BeanFactoryTransactionAttributeSourceAdvisor ,判断是否需要进行代理
* Can the given pointcut apply at all on the given class?
* <p>This is an important test as it can be used to optimize
* out a pointcut for a class.
* @param pc the static or dynamic pointcut to check 参数为 AnnotationTransactionAttributeSource
* @param targetClass the class to test
* @param hasIntroductions whether the advisor chain
* for this bean includes any introductions
* @return whether the pointcut can apply on any method
*/
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<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
//获取对应类的所有接口
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
/// 遍历
for (Class<?> clazz : classes) {
/// 获取所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
/// 判断是否符合pointcut
/// 调用 TransactionAttributeSourcePointcut#matches
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
/**
* Can the given advisor apply at all on the given class?
* This is an important test as it can be used to optimize
* out an advisor for a class.
* @param advisor the advisor to check
* @param targetClass class we're testing
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
/**
* Can the given advisor apply at all on the given class?
* <p>This is an important test as it can be used to optimize out an advisor for a class.
* This version also takes into account introductions (for IntroductionAwareMethodMatchers).
* @param advisor the advisor to check
* @param targetClass class we're testing
* @param hasIntroductions whether the advisor chain for this bean includes
* any introductions
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
/// 看下是不是IntroductionAdvisor
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) { // 查看BeanFactoryTransactionAttributeSourceAdvisor 是否支持
PointcutAdvisor pca = (PointcutAdvisor) advisor;
/// BeanFactoryTransactionAttributeSourceAdvisor 的 getPointcut返回的是 TransactionAttributeSourcePointcut, TransactionAttributeSourcePointcut的TransactionAttributeSource在前面注册了
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
现在回头看下 AnnotationTransactionAttributeSource
,TransactionAttributeSourcePointcut#match
用的就是AnnotationTransactionAttributeSource
/**
* TransactionAttributeSourcePointcut#matches
*/
@Override
public Boolean matches(Method method, Class<?> targetClass) {
// 自定义标签解析时注入,前面注入的 AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
代码语言:java复制/**
* AnnotationTransactionAttributeSource#getTransactionAttributeSource 调用父类 AbstractFallbackTransactionAttributeSource#getTransactionAttributeSource
* Determine the transaction attribute for this method invocation.
* <p>Defaults to the class's transaction attribute if no method attribute is found.
* @param method the method for the current invocation (never {@code null})
* @param targetClass the target class for this invocation (may be {@code null})
* @return a TransactionAttribute for this method, or {@code null} if the method
* is not transactional
*/
@Override
@Nullable
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 {
// 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 dta = (DefaultTransactionAttribute) txAttr;
dta.setDescriptor(methodIdentification);
dta.resolveAttributeStrings(this.embeddedValueResolver);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" methodIdentification "' with attribute: " txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
/**
* AbstractFallbackTransactionAttributeSource#computeTransactionAttribute
* Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
* <p>As of 4.1.8, this method can be overridden.
* @since 4.1.8
* @see #getTransactionAttribute
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow non-public methods, as configured. 非public方法,不管
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.
/// 看下是不是在目标类中
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;
}
/// 查找事务属性,都在 AnnotationTransactionAttributeSource
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
/**
* Determine the transaction attribute for the given method or class.
* <p>This implementation delegates to configured
* {@link TransactionAnnotationParser TransactionAnnotationParsers}
* for parsing known annotations into Spring's metadata attribute class.
* Returns {@code null} if it's not transactional.
* <p>Can be overridden to support custom annotations that carry transaction metadata.
* @param element the annotated method or class
* @return the configured transaction attribute, or {@code null} if none was found
*/
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
/// annotationParsers是在AnnotationTransactionAttributeSource初始化时加载的
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
/**
* 初始化,加载annotationParsers
* Create a custom AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* @param publicMethodsOnly whether to support public methods that carry
* the {@code Transactional} annotation only (typically for use
* with proxy-based AOP), or protected/private methods as well
* (typically used with AspectJ class weaving)
*/
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
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());
}
}
关注一下 SpringTransactionAnnotationParser
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.annotation;
import java.io.Serializable;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Strategy implementation for parsing Spring's {@link Transactional} annotation.
*
* @author Juergen Hoeller
* @author Mark Paluch
* @since 2.5
*/
@SuppressWarnings("serial")
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, 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());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
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;
}
@Override
public boolean equals(@Nullable Object other) {
return (other instanceof SpringTransactionAnnotationParser);
}
@Override
public int hashCode() {
return SpringTransactionAnnotationParser.class.hashCode();
}
}