Spring源码分析-(SpringBoot 事务)

Scroll Down

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-jdbcjar,所以存在PlatformTransactionManager的实现类,所以TransactionAutoConfiguration会被创建。同时看到在该注解上也有@Import(TransactionManagementConfigurationSelector.class),那就直接看TransactionManagementConfigurationSelectorselectImports方法。

@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;
    }
}

可以看到,在这里引入了AutoProxyRegistrarProxyTransactionManagementConfiguration就是里支持起来了整个事务的功能。这里主要注册了4个类,分别是通过如下方式注册:

  • AutoProxyRegistrar

    注册InfrastructureAdvisorAutoProxyCreator

  • ProxyTransactionManagementConfiguration

    注册BeanFactoryTransactionAttributeSourceAdvisorAnnotationTransactionAttributeSourceTransactionInterceptor

InfrastructureAdvisorAutoProxyCreator类结构如下

InfrastructureAdvisorAutoProxyCreator

可以看到InfrastructureAdvisorAutoProxyCreator间接实现了BeanPostProcessor.换句话说就是当Spring IOC实例Bean之后进行初始化的时候会执行postProcessBeforeInitializationpostProcessAfterInitialization方法.所以跟踪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的增强并且应用对应的增强。通过findCandidateAdvisorfindAdvisorsThatCanApply来处理

    	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,那我明白了这还是委托给这个拦截器了。看到其类结构:

    TransactionInterceptor

    这是实现了MethodInterceptor,所以当调用该代理类的方法的时候,会先执行

    TransactionInterceptor#invoke,可以说TransactionInterceptor支撑了整个事务的能力。

  • 创建代理对象.

    Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));