使用spring aop实现多事务源处理

2018-10-25  本文已影响0人  七玄之主

每段业务处理中专门去编写事务处理相关的逻辑相当麻烦,而且复制黏贴中也容易出错。采用切面编程的方式在业务方法执行之前自动开启事务,结束后根据执行状态再执行事务的回滚或提交操作。

事务逻辑实现的AOP处理类


@Aspect
@Component
@Slf4j
public class MultiTransactionalAop implements ApplicationContextAware {

    private ApplicationContext applicationContext = null;
    private TransactionStatus status = null;
    private PlatformTransactionManager transactionManager = null;
    private DefaultTransactionDefinition definition = null;

    /**
     * 执行方面前启动事务
     * @param point
     * @throws Exception
     */
    @Before("@annotation(MultiTransactional)")
    public void beforeAdvice(JoinPoint point) throws Exception {
        Class<?> className = point.getTarget().getClass();
        String methodName = point.getSignature().getName();
        Class<?>[] argClass = ((MethodSignature) point.getSignature())
                        .getParameterTypes();
        String transactionName = "";
        try {
            Method method = className.getMethod(methodName, argClass);
            if (method.isAnnotationPresent(MultiTransactional.class)) {
                MultiTransactional annotation = method
                                .getAnnotation(MultiTransactional.class);
                transactionName = annotation.value();
                transactionManager = (PlatformTransactionManager)applicationContext.getBean(transactionName);
                definition = new DefaultTransactionDefinition();
                definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                status = transactionManager.getTransaction(definition);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 事务正常完成时执行
     * @param point
     */
    @AfterReturning("@annotation(MultiTransactional)")
    public void afterReturningAdvice(JoinPoint point) {
        if (status != null && !status.isCompleted()) {
            transactionManager.commit(status);
            status = transactionManager.getTransaction(definition);
        }
    }

    /**
     * 事务出错时执行
     * @param point
     */
    @AfterThrowing(pointcut="@annotation(MultiTransactional)", throwing="e")
    public void afterThrowingAdvice(Throwable e) throws Throwable {
        if (status != null) {
            transactionManager.rollback(status);
        }
        throw e;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

自定义的事务注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface MultiTransactional {
    String value() default "默认开启事务管理类bean名称";
}

此AOP方式开启的事务不支持Service Bean 对象的嵌套方法,在使用 AOP 的时候,从IOC 容器中获取的 Service Bean 对象其实都是代理对象,而不是那些 Service Bean 对象本身,也就是说获取的并不是被代理对象或代理目标。当我在自己的 Service 类中使用 this 关键字嵌套调用同类中的其他方法时,由于 this 关键字引用的并不是该 Service Bean 对象的代理对象,而是其本身,故 Spring AOP 是不能拦截到这些被嵌套调用的方法的。

解决方法可以如下所示,通过调用自身来完成服务类中嵌套方式的触发。

@Autowired
private ApplicationContext applicationContext;
private ArtaKaiinRenkeiServiceImpl self;

@PostConstruct
private void init() {
    self = applicationContext.getBean(具体服务类.class);
}

具体使用如下所示

@MultiTransactional("事务管理类bean名称")
public void update(){
    // 业务逻辑实现
}

总的来说,借助AOP来实现事务的管理,能够将注意力放到具体的业务逻辑上,是代码逻辑更精简,同时避免复制事务代码时发生的一些因为遗漏产生的不易察觉的错误。实际使用中发现在开启多线程的情况下,发现所有线程操作的都是同一个事务对象,可能需要再事务开启时对于当前线程做对应处理,此部分目前还不明确,后续追加。

上一篇 下一篇

猜你喜欢

热点阅读