SpringBoot 事务自动装配
使用SpringBoot之后,只要正确的引用pom。只需要在启动类上增加@SpringBootApplication
注解即可了,在配置文件或者是配置中心中增加对应的数据源配置。然后就拥有了事务,那是怎么实现的呢
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
可以看到内部有@EnableAutoConfiguration
注解,观察到@Import
注解,该注解主要用于导入资源,通过Import注解把EnableAutoConfigurationImportSelector
引入IOC,在应用启动执行invokeBeanFactoryPostProcessors(beanFactory);
的时候,解析Class文件。执行selectImports
方法读取META-INF/spring-autoconfigure-metadata.properties
到当前容器中。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
在加载的AutoConfigurationMetadata其中找到org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration.ConditionalOnClass=org.springframework.transaction.PlatformTransactionManager
,由于我们引入spring-jdbc
jar,所以存在PlatformTransactionManager
的实现类,所以TransactionAutoConfiguration
会被创建。同时看到在该注解上也有@Import(TransactionManagementConfigurationSelector.class)
,那就直接看TransactionManagementConfigurationSelector
的selectImports
方法。
@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 {
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
@Override
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就是里支持起来了整个事务的功能。这里主要注册了4个类,分别是通过如下方式注册:
-
AutoProxyRegistrar
注册InfrastructureAdvisorAutoProxyCreator
-
ProxyTransactionManagementConfiguration
注册BeanFactoryTransactionAttributeSourceAdvisor,AnnotationTransactionAttributeSource,TransactionInterceptor,
InfrastructureAdvisorAutoProxyCreator
类结构如下
可以看到InfrastructureAdvisorAutoProxyCreator
间接实现了BeanPostProcessor
.换句话说就是当Spring IOC实例Bean之后进行初始化的时候会执行postProcessBeforeInitialization
和postProcessAfterInitialization
方法.所以跟踪InfrastructureAdvisorAutoProxyCreator
类定位在其父类AbstractAutoProxyCreator
中重写了这俩个方法。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
postProcessAfterInitialization
主要是用于找到对应bean的增强,然后根据增强去创建代理对象.
-
寻找Bean的增强并且匹配
通过**Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);**来找Bean的增强并且应用对应的增强。通过
findCandidateAdvisor
和findAdvisorsThatCanApply
来处理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; }
findCandidateAdvisors
方法定位为获取所有增强。首先通过BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);
获取所有的Advisor
类的beanName,然后通过getBean获取所有的实例,当然也包括我们之前注册的BeanFactoryTransactionAttributeSourceAdvisor
。findAdvisorsThatCanApply
方法定位为根据上述方法获取到增强和当前bean的Class是否匹配。public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } 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; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }
-
第一步优先处理处理引介增强
-
遍历所有增强器,然后过滤出非引介增强,并且对其进行处理。
记得我们在
findCandidateAdvisor
方法中获取到了BeanFactoryTransactionAttributeSourceAdvisor
,在这里通过pca.getPointcut(),
就取到了BeanFactoryTransactionAttributeSourceAdvisor.pointcut
,继续跟踪canApply
方法。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 ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
遍历该类所有接口和本身的方法。当遇到某个方法匹配,则证明当前的类适用于该增强。
不经有个疑问,那是怎样给方法进行匹配呢,我们在类上增加了
Transactional
注解就可以对所有的public
修饰的方法增加事务,这里还需要遍历整个方法,显然这是不符合使用的习惯的。继续跟踪methodMatcher.matches(method, targetClass)
.发现是执行TransactionAttributeSourcePointcut#matches
,实际执行的代码则是tas.getTransactionAttribute(method, targetClass)
,这里的tas则是AbstractFallbackTransactionAttributeSource
对象。public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; } Object cacheKey = getCacheKey(method, targetClass); TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return 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.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }
这方法也没给我解惑,一贯的从缓存加载,缓存没有走
computeTransactionAttribute(method, targetClass);
.委托的我扎心。protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); 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; }
该方法定位只提取
public
修饰的方法 首先获取下该方法的事务标签,存在的话。直接返回,放入缓存。不存在则需要去判断该方法所在类的事务标签,当前类没有,则去其超类接口去寻找。怎么找事务标签,还是直接定位findTransactionAttribute
方法吧,最终调用AnnotationTransactionAttributeSource#determineTransactionAttribut
,使用this.annotationParser
去解析,实际是使用SpringTransactionAnnotationParser
解析。@Nullable protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; }
定位解析方法,找到
Transactional
注解,舒服了。public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } } 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")); 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; }
怎样给方法进行匹配。到现在终于明白了,其实就是匹配对应方法的事务标签。同时明白了事务工作的初始准备工作是怎样实现,当判断某个bean被事务标记增强的时候,就会去使用
BeanFactoryTransactionAttributeSourceAdvisor
增强,进而扩充注入类支持事务能力。理解了那还是不知道如何触发事务呢。➳♥゛在注册
BeanFactoryTransactionAttributeSourceAdvisor
我们看到了,添加了TransactionInterceptor
,那我明白了这还是委托给这个拦截器了。看到其类结构:这是实现了
MethodInterceptor
,所以当调用该代理类的方法的时候,会先执行TransactionInterceptor#invoke
,可以说TransactionInterceptor
支撑了整个事务的能力。 -
-
创建代理对象.
Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));