zoukankan      html  css  js  c++  java
  • Spring源码解析(七) -- Spring事务-初始化篇

      spring中事务也是很重要的知识点,有了之前的aop的知识,分析事务源码会更容易懂。

      1 事务入口

      要想使用事务,就需要在配置文件里加tx命名空间。同时配置文件里要这么配 <tx:annotation-driven transaction-manager="transactionManager" />。所以分析事务源码也从解析tx命名空间开始。

      在spring-tx.jar包下找META-INF里的spring.handlers配置文件里,找到这么句话

      http://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

      这个org.springframework.transaction.config.TxNamespaceHandler就是spring事务的开端。

    @Override
        public void init() {
            registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
            registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
            registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
        }

      

    class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    
        /**
         * Parses the {@code <tx:annotation-driven/>} tag. Will
         * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
         * with the container as necessary.
         */
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            registerTransactionalEventListenerFactory(parserContext);
            String mode = element.getAttribute("mode");
            if ("aspectj".equals(mode)) {
                // mode="aspectj"
                registerTransactionAspect(element, parserContext);
            }
            else {
                // mode="proxy"
                AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
            }
            return null;
        }
    AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext)是十分重要的。
    public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
                AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
    
                String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
                if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
                    Object eleSource = parserContext.extractSource(element);
    
                    // Create the TransactionAttributeSource definition.
                    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.
                    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);
    
                    // 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);
    
                    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);
                }
            }
        }

      首先分析下  AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
            return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
        }

      能看到在spring的声明周期内,InfrastructureAdvisorAutoProxyCreator将作为所有aop的实现者,事务只是其中一个增强。

    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
                BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
                if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                    int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                    int requiredPriority = findPriorityForClass(cls);
                    if (currentPriority < requiredPriority) {
                        apcDefinition.setBeanClassName(cls.getName());
                    }
                }
                return null;
            }

      注意上面的两行代码 currentPriority, requiredPriority。我们在上节中通过分析我们使用的aop增强器是AnnotationAwareAspectJAutoProxyCreator,但是整个spring生命周期内只能有一个aop的增强器。spring是通过增强器的优先级来决定留下哪一个,优先级就是那个在list中的index最大用哪个。

      AopConfigUtils 

    static {
            APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
            APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
            APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
        }

      可以看到 AnnotationAwareAspectJAutoProxyCreator 的优先级是高于 InfrastructureAdvisorAutoProxyCreator,所以对于引入了事务的spring,唯一留下的增强器就是AnnotationAwareAspectJAutoProxyCreator。

      回到  configureAutoProxyCreator方法继续分析。

    String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
                if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName))

      if说明对于tx标签的解析只会做一次,就是说在配置文件里配两个事物管理器是没用的。

      接下来就是注册了三个BeanDefinition。这三个bd也是spring事务的核心。简单是解释下作用

      AnnotationTransactionAttributeSource      事务的属性,常见的就是传播行为,隔离级别,回滚配置。AnnotationTransactionAttributeSource是功能类,专门用来解析方法上的事务属。

      TransactionInterceptor                                    它是一个advice,就是增强逻辑的具体实现

      BeanFactoryTransactionAttributeSourceAdvisor  从名字看就知道了,这是一个advisor。在进行代理的时候,会被找出来并转为Interceptor执行。

      这三个bean的关系是 BeanFactoryTransactionAttributeSourceAdvisor有两个成员变量就是AnnotationTransactionAttributeSource 和 TransactionInterceptor                                

    public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    
        private TransactionAttributeSource transactionAttributeSource;
    
        private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
            @Override
            protected TransactionAttributeSource getTransactionAttributeSource() {
                return transactionAttributeSource;
            }
        };
    public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
    
        private String adviceBeanName;
    
        private BeanFactory beanFactory;
    
        private transient volatile Advice advice;
    
        private transient volatile Object adviceMonitor = new Object();
    public interface Interceptor extends Advice {
    
    }

      其实我们在上一节的aop中讲过,可以简单理解advisor就是advice + pointcut,BeanFactoryTransactionAttributeSourceAdvisor当然也是不例外的,只不过 它还有个TransactionAttributeSource

    用来解析被代理类的每个方法的事务属性,也就是说它的pointcut就是通过TransactionAttributeSource来辅助实现的。

      跟aop一样,对一个类增强就是要获取能对他切的advisor,那么对于事务其判断逻辑就是被代理类或者它的任意一个方法是否有@Transanctional注解。

      这部分代码比较繁琐,层层嵌套,在本阶段就不分析了。

    二 初始化

      上文提到了命名空间解析替我们注入了三个bean,那么这几个bean是怎么注入的

      现在看  AbstractAutoProxyCreator.wrapIfNecessary 

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
                return bean;
            }
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
    
            // Create proxy if we have advice.
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

       BeanFactoryAdvisorRetrievalHelper 

    public List<Advisor> findAdvisorBeans() {
            // Determine list of advisor bean names, if not cached already.
            String[] advisorNames = null;
            synchronized (this) {
                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!
                    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Advisor.class, true, false);//从BeanDefinition缓存中拿到所有的类型Advisor的名字
                    this.cachedAdvisorBeanNames = advisorNames;
                }
            }
            if (advisorNames.length == 0) {
                return new LinkedList<Advisor>();
            }
    
            List<Advisor> advisors = new LinkedList<Advisor>();
            for (String name : advisorNames) {
                if (isEligibleBean(name)) {
                    if (this.beanFactory.isCurrentlyInCreation(name)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Skipping currently created advisor '" + name + "'");
                        }
                    }
                    else {
                        try {
                            advisors.add(this.beanFactory.getBean(name, Advisor.class));//获取Bean
                        }

      上面的代码就能看出来了,是什么时候初始化的 事务相关的advisor的。

      

      另外,再多提一点。事务增强和用户自己使用@Aspect注解实现的aop在执行时有稍微不同。

    ReflectiveMethodInvocation 
    
    @Override
        public Object proceed() throws Throwable {
            //    We start with an index of -1 and increment early.
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return invokeJoinpoint();
            }
    
            Object interceptorOrInterceptionAdvice =
                    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                // Evaluate dynamic method matcher here: static part will already have
                // been evaluated and found to match.
                InterceptorAndDynamicMethodMatcher dm =
                        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                    return dm.interceptor.invoke(this);                            //@Aspect实现的aop在这里执行
                }
                else {
                    // Dynamic matching failed.
                    // Skip this interceptor and invoke the next in the chain.
                    return proceed();
                }
            }
            else {
                // It's an interceptor, so we just invoke it: The pointcut will have
                // been evaluated statically before this object was constructed.
                return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); //事务的增强在这里
            }
        }

      好了,关于事务的aop代理部分就到这里,我们知道了spring是如何把事务增强的advisor引入到spring容器中,下一节就要看spring事务在执行方法时的具体实现。

    后记   

      如果一个Service里面有不需要增强的方法spring是怎么处理的呢?

      现在来看  JdkDynamicAopProxy.public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

      整个方法很长只截取一部分。如果一个方法上没有@Transactional,这里 getInterceptorsAndDynamicInterceptionAdvice 返回的就是空数组

           // Get the interception chain for this method.
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
                // Check whether we have any advice. If we don't, we can fallback on direct
                // reflective invocation of the target, and avoid creating a MethodInvocation.
                if (chain.isEmpty()) {
                    // We can skip creating a MethodInvocation: just invoke the target directly
                    // Note that the final invoker must be an InvokerInterceptor so we know it does
                    // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                }

      此时就是通过反射直接执行。

       getInterceptorsAndDynamicInterceptionAdvice 这个方法很有意思,里面会对执行过的方法进行缓存,这样下次在执行就不用重新扫描了。

      

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
            MethodCacheKey cacheKey = new MethodCacheKey(method);
            List<Object> cached = this.methodCache.get(cacheKey);
            if (cached == null) {
                cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(//把每个advisor都拿出来,挨个匹配
                        this, method, targetClass);
                this.methodCache.put(cacheKey, cached);
            }
            return cached;
        }

      

  • 相关阅读:
    各种快递查询Api接口(快递鸟)
    验证码识别,发票编号识别
    ugui自制摇杆。
    个人网站
    unity访问php
    其实我是学文学的
    unity发布ios游戏总结
    Unity连接本地数据库sqlite
    gcc中gdb调试工具的使用
    windows系统下调试uCOS-II
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13822603.html
Copyright © 2011-2022 走看看