美文网首页程序员
tx:annotation-driven浅析

tx:annotation-driven浅析

作者: nextbeginning | 来源:发表于2019-04-03 16:56 被阅读0次

    引入流程

    现在一般用解式事务比较多,而注解事务的启用方式有两种:

    1. 在有@Configuration的类上使用@EnableTransactionManagement注解
    2. 在xml中使用tx:annotation-driven
      具体使用方法请参照引入spring事务管理,本文主要是针对注解式事务的整个运作流程进行浅析。
    <beans xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd">
        <tx:annotation-driven transaction-manager="txManager"/>
    </beans>
    

    解析自定义xml标签

    xml自定义标签解析需要在项目的/META-INF/spring.schemas目录中指定namespace文件的路径,在/META-INF/spring.handlers指定解析该namespace的类。通常我们定义的解析类都继承自NamespaceHandlerSupport,然后为每个xml标签定义一个实现了BeanDefinitionParser的解析类,在parse方法中将xml解析成BeanDefinition。可以参考下spring-tx包中的使用案例。

    /META-INF/spring.schemas
    http\://www.springframework.org/schema/tx/spring-tx-4.0.xsd=org/springframework/transaction/config/spring-tx-4.0.xsd
    
    /META-INF/spring.handlers
    http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
    
    #TxNamespaceHandler
    public class TxNamespaceHandler extends NamespaceHandlerSupport {
        @Override
        public void init() {
            registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
            registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
            registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
        }
    }
    

    解析xml中的tx:anotation-driven标签

    使用注解式事务,@Transactional只是定义了事务的传播特性和隔离级别等属性。要达到管理事务的效果,必须为目标对象生成代理。AnnotationDrivenBeanDefinitionParser的parse方法,使用AopAutoProxyConfigurer类来配置代理创建器InfrastructureAdvisorAutoProxyCreator。

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        // mode="proxy"
        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }
    ...
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
    }
    

    生成代理创建器后,继续添加事务advisor:BeanFactoryTransactionAttributeSourceAdvisor

    RootBeanDefinition sourceDef = new RootBeanDefinition(
            "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
    sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
    
    // Create the TransactionInterceptor definition.
    RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
    interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registerTransactionManager(element, interceptorDef);
    interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
    String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
    
    // Create the TransactionAttributeSourceAdvisor definition.
    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")) {
        advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
    }
    parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
    

    从之前spring tx解析xml中的tx:annotation-driven流程中,我们发现它创建了四个对象到容器中,这四个容器对象的Role都是ROLE_INFRASTRUCTURE,后续代码会用到这个属性,不对拥有这个属性的对象进行代理。下面我们将详细对着四个对象进行分析:

    • org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
    • org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
    • org.springframework.transaction.interceptor.TransactionInterceptor
    • org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor

    代理创建器InfrastructureAdvisorAutoProxyCreator

    InfrastructureAdvisorAutoProxyCreator是代理对象的管理类,它扫描factory中所有的advisor,调用对应的pointcut检测需要当前对象是否需要创建代理,并把advice应用到目标类上,生成代理。从InfrastructureAdvisorAutoProxyCreator的类图中可以看到,该类主要的逻辑点在其父类AbstractorAutoProxyCreator中。


    InfrastructureAdvisorAutoProxyCreator

    postProcessBeforeInstantiation将基础设施类排除代理范围。如果有TargetSourceCreator,则在这步会调用TargetSourceCreator返回对象。

    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);
        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        if (beanName != null) {
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                this.targetSourcedBeans.add(beanName);
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
                Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
        }
        return null;
    }
    

    通常情况是在postProcessAfterInitialization中完成生成代理对象的过程的,调用wrapIfNecessary来生成代理对象。如果是预加载的对象,则是在SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference接口进行创建代理对象的。

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    

    wrapIfNecessary方法内部找到当前对象的advisor(如果存在),然后创建代理对象

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // Create proxy if we have advice.
        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;
    }
    

    给Bean查找Advice和Advisor的过程是先调用org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(),该方法从bean factory中查找实现了org.springframework.aop.Advisor的对象

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

    这里会查找到之前解析tx:annotation-driven时候,添加的BeanFactoryTransactionAttributeSourceAdvisor。这个advisor的pointcut用的是TransactionAttributeSourcePointcut,advice用的是TransactionInterceptor


    BeanFactoryTransactionAttributeSourceAdvisor

    先来看看切入点规则,从TransactionAttributeSourcePointcut的类图中可以看到,该切入点的类过滤器是TRUE,即所有的类都符合条件。方法过滤器MethodMatcher则调用TransactionAttributeSource接口的getTransactionAttribute方法来判断是否符合需要代理的条件。


    TransactionAttributeSourcePointcut
    public boolean matches(Method method, Class<?> targetClass) {
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
    

    在之前解析tx:annotation-driven时,给切入点使用的TransactionAttributeSource的实现类是AnnotationTransactionAttributeSource,该类的父类AbstractFallbackTransactionAttributeSource最终调用子类的findTransactionAttribute去获取TransactionAttribute属性。

    public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
        ...
        TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
    }
    
    private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
        ...
        txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
    }
    

    AnnotationTransactionAttributeSource内部通过SpringTransactionAnnotationParser去将注解转换成TransactionAttribute,查找的过程是递归查找,即支持你自定义一个注解,在自定义注解上配置@Transactional(xxx="xxx"), 然后用自定义注解也可以达到效果。

    protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
        return determineTransactionAttribute(clazz);
    }
    protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
        for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
            TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
            if (attr != null) {
                return attr;
            }
        }
        return null;
    }
    

    分析完注解式事务的切点之后,再结合InfrastructureAdvisorAutoProxyCreator判断是否要代理对象的逻辑,就非常清晰了。

    #org.springframework.aop.support.AopUtils.canApply(Pointcut, Class<?>, boolean)
    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }
    
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class<?> clazz : classes) {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if (methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }
        return false;
    }
    

    pointcut流程梳理完了,再来看看advice。解析xml中的annotation-driven的时候,使用的advice是TransactionInterceptor。最终通过invokeWithinTransaction来给目标方法进行事务管理。


    TransactionInterceptor
    public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            @Override
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
        });
    }
    

    本文针对注解式事务的实现流程进行分析,关于spring事务具体的执行流程即TransactionInterceptor类的内部逻辑请参考后续文章。关于spring事务的使用方法请参考:引入spring事务

    相关文章

      网友评论

        本文标题:tx:annotation-driven浅析

        本文链接:https://www.haomeiwen.com/subject/bgtlbqtx.html