• SpringAOP[8]如何自动代理@Transactional


    事务的自动代理器为InfrastructureAdvisorAutoProxyCreator,若同时注册多个AbstractAutoProxyCreator子类,可能会存在多处代理的情况。

    多次代理的效果如下图所示:

     

    为什么该类会被二次代理呢?

    @Configuration
    @EnableTransactionManagement  //注册了一个自动代理器
    public class DefaultAdvisorAutoProxyCreatorConfig {
        //目标类
        @Bean("tService")
        public TService tService() {
            return new TService();
        }
        //注册了一个自动代理器
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); //启用cglib代理
            return defaultAdvisorAutoProxyCreator;
        }
    }
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext =
                    new AnnotationConfigApplicationContext(DefaultAdvisorAutoProxyCreatorConfig.class);
            //可以使用@Primary指定元素,或直接使用name名获取。
            TService bean = (TService) applicationContext.getBean("tService");
            bean.say();
        }

    上述代码实际上注册了两个自动代理器,而他们均是继承于org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

     

      

    AbstractAutoProxyCreator类作用是为Bean生成代理对象,如何获取到beanAdvisor。它是交由了子类去实现。

    AbstractAdvisorAutoProxyCreator作为子类,实现了自动获取Advisor的逻辑(实现了getAdvicesAndAdvisorsForBean)。


    1. 自动代理含义

    1. 获取整个Spring容器Advisor类型的bean,由生成器决定是否处理该Advisor。(若多个生成器均决定处理一个Advisor,可能存在二次代理)。

    2. 每个生成器开始遍历自己决定处理的Advisor。通过Advisor的pointcut查看是否能切入bean。返回所有能够切入的Advisor。

    3. 创建Proxy时,将能切入的Advisor传入,即完成自动代理。

    解决上述二次代理的问题,即不要去注册defaultAdvisorAutoProxyCreator

    2. 事务增强器织入bean

    首先解析类/方法上的事务注解,若存在则解析为属性对象。那么如何判断注解是否存在?且如何解析为属性对象?

    先抛开源码,看两个main函数(不依赖Spring容器)

    2.1 解析自定义标签

    自定义注解:

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface MyTransaction {
        String value() default "";
    }
    public class TService {
        @MyTransaction("解析自定义注解")
        public void run1() {
            System.out.println("This is a run1() Method!");
        }
        @Transactional
        public void say() {
            log.info("说话...");
        }
    }

    解析注解:

        @Test
        public void test4() throws NoSuchMethodException {
            Method method = TService.class.getMethod("run1");
            //读取事务注解
            AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
                    method, MyTransaction.class, false, false);
            System.out.println(attributes);
        }

    2.2 解析事务标签

    得到的AnnotationAttributes对象,如何转化为一个我们自定义的属性对象呢

    public void test1() throws NoSuchMethodException {  
        Method say = TService.class.getMethod("say");  
        //读取事务注解  
        AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(  
                say, Transactional.class, false, false);  
        //脱离Spring  
        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);  
        System.out.println(JSON.toJSONString(rbta));  
    }  

    有小伙伴此时一定会好奇RollbackRuleAttribute对象是干啥的。

    @Test  
    public void test3() {  
        RollbackRuleAttribute rollbackRuleAttribute = new RollbackRuleAttribute(ArithmeticException.class);  
        try {  
            throw new BusinessException("业务异常");  
        } catch (Exception e) {  
            //判断抛出的e(及其父类)是否是ArithmeticException异常  
            int depth = rollbackRuleAttribute.getDepth(e);  
            System.out.println(depth);  
        }  
    }  

    也就是说,若异常(及其父类)符合指定的异常,返回正数;否则返回-1;
    这样的话,就能决定是否是回滚的异常。

    此时,注解标签解析为了属性对象。

    2.3 Spring的事务切点

    判断方法是否匹配时,会遍历bean中所有访问权限的方法。Spring会遍历public方法,判断该method/class上是否存在Transactional注解。若存在,解析为属性对象,且通过匹配。

    3. Spring解析事务注解

    3.1 增强器的注册

    首先需要存在一个Advisor负责去增强@Transactional标签的方法。
    注意:BeanFactoryTransactionAttributeSourceAdvisor实现的是PointcutAdvisor接口,既可以设置Advice,又可以设置Pointcut。
    但是下面代码中只配置了Adice,而pointcut是由BeanFactoryTransactionAttributeSourceAdvisor类完成的配置。
    @Configuration
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
        //注册了Advisor
        @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)  //声明的role为基础类(Spring内部使用的类)
        public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
            BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
            advisor.setTransactionAttributeSource(transactionAttributeSource());
           //配置Advice
            advisor.setAdvice(transactionInterceptor());
            if (this.enableTx != null) {
                advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
            }
            return advisor;
        }
    
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionAttributeSource transactionAttributeSource() {
            return new AnnotationTransactionAttributeSource();
        }
        //注册了Advice
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionInterceptor transactionInterceptor() {
            TransactionInterceptor interceptor = new TransactionInterceptor();
            interceptor.setTransactionAttributeSource(transactionAttributeSource());
            if (this.txManager != null) {
                interceptor.setTransactionManager(this.txManager);
            }
            return interceptor;
        }
    }
    public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    
        @Nullable
        private TransactionAttributeSource transactionAttributeSource;
        //pointcut 是TransactionAttributeSourcePointcut 的子类,实现了TransactionAttributeSource 方法。
        //该方法的作用,是用户可以配置`解析器`。
        private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
            @Override
            @Nullable
            protected TransactionAttributeSource getTransactionAttributeSource() {
                return transactionAttributeSource;
            }
        };
    }

    3.2 方法匹配

    如何判断bean方法符合规则?判断是否能获取事务属性对象。

    自动代理器会遍历bean的所有方法,判断是否与MethodMatcher匹配。实际上会调用TransactionAttributeSourcePointcutmatches方法。

    abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
    
        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            TransactionAttributeSource tas = getTransactionAttributeSource();
            //若TransactionAttributeSource 对象不为空,那么获取方法上的事务属性对象。
            return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
        }
        //抽象方法,但是注册的Advisor中的pointcut是TransactionAttributeSourcePointcut 子类。
        //实际上获取的是TransactionAttributeSource 对象
        @Nullable
        protected abstract TransactionAttributeSource getTransactionAttributeSource();
    }

    3.3 事务属性获取

    解析事务注解,获取事务属性对象。

    实际上TransactionAttributeSource为3.1配置的AnnotationTransactionAttributeSource对象。

    当然这个类实现的只是特有的方法,而算法骨干由其父类AbstractFallbackTransactionAttributeSource实现。

    注意getTransactionAttribute方法返回null,则证明pointcut不匹配bean的某方法。

    public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
    
        @Override
        @Nullable
        public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            //若是Object的方法,直接返回null
            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 对象的核心方法(如下所示)
                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;
            }
        }
        @Nullable
        protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
            // 该方法是否要求必须是public级别(因为自动代理会对所有方法进行代匹配)
            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) {
                // Fallback is to look at the original method.
                txAttr = findTransactionAttribute(method);
                if (txAttr != null) {
                    return txAttr;
                }
                // Last fallback is the class of the original method.
                txAttr = findTransactionAttribute(method.getDeclaringClass());
                if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                    return txAttr;
                }
            }
            return null;
        }
    
    }

    下图的两个抽象方法,由子类实现。

     

    还需要注意的一个细节,AnnotationTransactionAttributeSource是其唯一子类。
    public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
            implements Serializable {
        public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
            this.publicMethodsOnly = publicMethodsOnly;
            if (jta12Present || ejb3Present) {
                this.annotationParsers = new LinkedHashSet<>(4);
                this.annotationParsers.add(new SpringTransactionAnnotationParser());
                if (jta12Present) {
                    this.annotationParsers.add(new JtaTransactionAnnotationParser());
                }
                if (ejb3Present) {
                    this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
                }
            }
            else {
                //通用模式下,为SpringTransactionAnnotationParser解析器
                this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
            }
        }
        @Override
        @Nullable
        protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
            return determineTransactionAttribute(clazz);
        }
    
        @Override
        @Nullable
        protected TransactionAttribute findTransactionAttribute(Method method) {
            return determineTransactionAttribute(method);
        }
        //遍历解析器,获取事务注解(方法如2.2所示)
        @Nullable
        protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
            for (TransactionAnnotationParser parser : this.annotationParsers) {
                TransactionAttribute attr = parser.parseTransactionAnnotation(element);
                if (attr != null) {
                    return attr;
                }
            }
            return null;
        }
    }

    parseTransactionAnnotation()方法如2.2所示,遍历方法/类上的事务注解。获取到TransactionAttribute对象。

    MethodMatcher返回true,则证明该方法可以被事务增强器去增强。将Advisor加入到List中,并开始处理下一个Advisor。最终获取到所有可切入的Advisor。去创建代理对象。

     
  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15559352.html
Copyright © 2020-2023  润新知