Spring-AOP基础概念,及实际应用中遇到的问题

一、基础概念

二、实际应用中遇到的问题

1、aop与事务的执行顺序问题

1)问题描述

在使用aop时遇到一个这样问题:需求是用户信息更新后,要使用aop将更新后的信息,推送到其他系统;但是,实际使用时用户更新后,推送功能推的用户数据却是更新前的数据。

我们用的是@AfterReturning通知,按理说是在更新方法执行后才开始推送的,这时期望的是数据库中的用户信息已经更新,我们查出用户信息再推送、应该是最新的数据。

问题出在,更新方法要进行多个表的数据修改、使用了事务。所以,虽然更新方法先执行(更新用户和其他表)、aop通知方法后执行(查询用户和推送),但有些情景、比如数表中数据过多时,更新方法先执行但是在多个数据库修改操作没有完成前,事务不提交、表中用户数据不更新;这时aop查询方法“后发先至”,在用户数据更新之前先完成查询,就得到了错误数据。

2)解决方法

应该有很多解决方法,我这里是这样实现的:
首先,是否有和当前线程有关联的事务正在执行、是可以知道的,

boolean flag = TransactionSynchronizationManager.isActualTransactionActive();

spring提供的这个方法,当有相关的、正在执行事务时,返回true;
其次,TransactionSynchronizationManager提供了多个方法,可以让我们实现在事务提交过程的各个时间节点,执行我们的方法

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                    @Override
                    public void suspend() {

                    }

                    @Override
                    public void resume() {

                    }

                    @Override
                    public void flush() {

                    }

                    @Override
                    public void beforeCommit(boolean b) {

                    }

                    @Override
                    public void beforeCompletion() {

                    }

                    @Override
                    public void afterCommit() {
                        //执行事务提交后流程
                    }

                    @Override
                    public void afterCompletion(int i) {
                        //执行事务完成后流程
                    }
                });

所以我先判断当前线程是否有关联的事务正在执行?
如果有就在事务完成后再执行我的方法(事务提交后就执行应该就行),
如果没有,那就马上执行的方法。
注意:这些逻辑,要在aop通知方法中执行
具体代码如下

/**
 * @Description 用户数据推送
 **/
@Aspect
@Component
public class PushUserInfoAspect{

    private static ExecutorService threadPool = Executors.newFixedThreadPool(500);

    @Around("@annotation(pushDataToShop)")
    public Object around(ProceedingJoinPoint joinPoint, PushDataToShop pushDataToShop) throws Throwable{
        	//JSONObject param = getNameAndValue(joinPoint);
            String event = pushDataToShop.event();
            String dataPlace = pushDataToShop.value();
            JSONObject argObj = getNameAndValue(joinPoint);
            Object returnValue = joinPoint.proceed();
            JSONObject returnJsonOb = (JSONObject) JSONObject.toJSON(returnValue);
            //获取
            boolean flag = TransactionSynchronizationManager.isActualTransactionActive();
            //判断是否存在事务正在执行
            if(flag){
                //1.1 存在事务
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                    @Override
                    public void suspend() {

                    }

                    @Override
                    public void resume() {

                    }

                    @Override
                    public void flush() {

                    }

                    @Override
                    public void beforeCommit(boolean b) {

                    }

                    @Override
                    public void beforeCompletion() {

                    }

                    @Override
                    public void afterCommit() {
                        //执行事务提交后流程
                    }

                    @Override
                    public void afterCompletion(int i) {
                        try {
                            excutePush(returnJsonOb,argObj,dataPlace,event);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            } else {
            //1.2 没有事务
                excutePush(returnJsonOb,argObj,dataPlace,event);
            }
            return returnValue;
    }

    /**
      * @Description 执行用户推送
     **/
    public void excutePush(JSONObject returnObj,JSONObject argObj,String dataPlace,String event) throws Exception{
        。。。
    }
}

补充:因为事务底层,也是通过aop实现的,而aop的执行顺序可以配置,所以还能通过直接配置事务与aop的执行顺序,解决上述问题。

你可能感兴趣的:(后端,spring,java,后端)