周口网站建设定制zkweb网站seo诊断分析报告
参考文章:
《Spring事务源码解析之tx:annotation-driven标签解析》
《Spring 源码解析—事务执行》
参考资料:
《Spring AOP源码:开启注解读取》
《Spring AOP源码2:查找增强器》
《Spring AOP源码3:实现代理》
写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。
前言
本文我们介绍下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
1、TxNamespaceHandler
2、AnnotationDrivenBeanDefinitionParser
二、、AopAutoProxyConfigurer
1、注册自动代理创建器
1.1、注册InfrastructureAdvisorAutoProxyCreator
1.2、设置proxy-target-class和expose-proxy属性
1.3、注册ComponentDefinition
2、注册了事务管理器等Bean
2.1、创建AnnotationTransactionAttributeSource
2.2、创建TransactionInterceptor
2.3、创建BeanFactoryTransactionAttributeSourceAdvisor
三、代理对象的创建
1、InfrastructureAdvisorAutoProxyCreator
2、canapply
2.1、getMethodMatcher
2.2、getTransactionAttribute
2.3、computeTransactionAttribute
2.4、findTransactionAttribute
2.5、parseTransactionAnnotation
补充
事务仅对 public 方法有效
一、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。
@Overridepublic void init() {registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());}
2、AnnotationDrivenBeanDefinitionParser
下面就来到了AnnotationDrivenBeanDefinitionParser的parse方法,因为Spring事务管理也是基于创建代理类来实现的,因此和AOP一样首先需要创建代理创建器。
@Overridepublic 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) {// 向容器中注册InfrastructureAdvisorAutoProxyCreatorBeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 设置proxy-target-class和expose-proxy配置useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);// 注册ComponentDefinitionregisterComponentIfNecessary(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);// 判断容器中有无internalTransactionAdvisorString 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.javastatic 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,则返回加上前缀&的&beanNameObject 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。
@Overridepublic Pointcut getPointcut() {return this.pointcut;}private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {@Overrideprotected 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方法上生效。