Java教程

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

本文主要是介绍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。去创建代理对象。

 

 

这篇关于SpringAOP[8]-如何自动代理@Transactional的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!