All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dreamroute.tx.manager.starter.config.TxManagerAutoConfiguration Maven / Gradle / Ivy

package com.github.dreamroute.tx.manager.starter.config;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

/**
 * @author w.dehai.2021/7/20.11:37
 */
@Slf4j
@Aspect
@Configuration
@EnableConfigurationProperties(TxManagerProperties.class)
public class TxManagerAutoConfiguration {

    @Resource
    private TxManagerProperties properties;
    @Resource
    private TransactionManager txManager;

    @Bean
    public TransactionInterceptor txAdvice() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        // 只读事务
        RuleBasedTransactionAttribute readOnly = null;
        if (properties.isEnableReadOnly()) {
            readOnly = new RuleBasedTransactionAttribute();
            readOnly.setReadOnly(true);
        }

        // 普通事务
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        String rollbackFor = properties.getRollbackFor();
        Class exceptionCls = rollbackException(rollbackFor);
        required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(exceptionCls)));

        Map methods = processExpress(required, readOnly);
        source.setNameMap(methods);
        return new TransactionInterceptor(txManager, source);
    }

    @Bean(name = "txAdviceAdvisor")
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        String packages = properties.getPackages();
        if (isEmpty(packages)) {
            throw new IllegalArgumentException("配置tx.manager.packages是必填项,表示需要执行事务的包!");
        }
        String execution = Arrays.stream(packages.split(",")).map(e -> "execution(* " + e.trim() + "..*.*(..))").collect(Collectors.joining(" || "));
        pointcut.setExpression(execution);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }

    private Map processExpress(RuleBasedTransactionAttribute required, RuleBasedTransactionAttribute readOnly) {
        Map methods = new HashMap<>();
        methods.put("*", required);

        methods.put("list*", readOnly);
        methods.put("get*", readOnly);
        methods.put("find*", readOnly);
        methods.put("page*", readOnly);
        methods.put("count*", readOnly);
        methods.put("query*", readOnly);
        methods.put("select*", readOnly);

        String ro = properties.getReadOnly();
        String rd = properties.getRequired();
        if (isNotBlank(ro)) {
            Arrays.stream(ro.split(",")).map(String::trim).forEach(r -> methods.put(r, readOnly));
        }
        if (isNotEmpty(rd)) {
            Arrays.stream(rd.split(",")).map(String::trim).forEach(r -> methods.put(r, required));
        }
        return methods;
    }

    private Class rollbackException(String rollbackFor) {
        Class exceptionCls;
        try {
            exceptionCls = this.getClass().getClassLoader().loadClass(rollbackFor);
            if (!Exception.class.isAssignableFrom(exceptionCls)) {
                throw new IllegalArgumentException("配置tx.manager.rollback-for必须是异常类型");
            }
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("配置tx.manager.rollback-for不允许使用: " + rollbackFor);
        }
        return exceptionCls;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy