Spring声明式事务和@Aspect的拦截顺序问题的解决

作者:Matchstick 时间:2023-07-18 12:10:46 

在使用AbstractRoutingDataSource配置多数据源时,发现使用@aspect配置的DataSourceSwitchAspect总是在声明式事务之后执行,配置了Order依然不行,经过调研发现是由于两者的aop代理方式不一致导致。

在spring内部,是通过BeanPostProcessor(《spring 攻略》一书中翻译为,后处理器)来完成自动创建代理工作的。根据匹配规则的不同大致分为三种类别: 1、匹配Bean的名称自动创建匹配到的Bean的代理,实现类BeanNameAutoProxyCreator 2、根据Bean中的AspectJ注解自动创建代理,实现类AnnotationAwareAspectJAutoProxyCreator 3、根据Advisor的匹配机制自动创建代理,会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中,实现类DefaultAdvisorAutoProxyCreator

其中@Aspect声明的aop是通过AnnotationAwareAspectJAutoProxyCreator进行代理的,而项目中的声明式事务是BeanNameAutoProxyCreator方式进行代理的,经调试发现BeanNameAutoProxyCreator拦截优先级高于AnnotationAwareAspectJAutoProxyCreator,order配置只对同一类型的aop拦截方式起作用,如下:

DataSourceSwitchAspect


/**
* 数据源切换切面
* @author Matchstick
*/
@Aspect
@Order(1) //确保该切面在transaction之前执行
@Component
public class DataSourceSwitchAspect
{
private Logger logger = LoggerFactory.getLogger(getClass());

@Pointcut("@annotation(com.etu.multidatasource.test.datasource.DataSourceId)")
public void pointcut(){}

@Before("@annotation(dataSourceId)")
public void switchDataSource(JoinPoint point, DataSourceId dataSourceId)
{
String dsId = dataSourceId.value();
MultiDataSourceContextHolder.setDataSourceId(dsId);
logger.debug("switch datasource -> {}", dsId);
}

@After("@annotation(dataSourceId)")
public void restoreDataSource(JoinPoint point, DataSourceId dataSourceId)
{
MultiDataSourceContextHolder.removeDataSourceId();
logger.debug("restore datasource -> {}",         MultiDataSourceContextHolder.getDefaultDataSourceId());
}
}

DataSourceConfig


@Bean
public BeanNameAutoProxyCreator txProxy()
{
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
creator.setInterceptorNames("txAdvice");
creator.setBeanNames("*Service", "*ServiceImpl");
creator.setProxyTargetClass(true);
creator.setOrder(2);
return creator;
}

解决方案:要么修改DataSourceSwitchAspect的aop方式为BeanNameAutoProxyCreator,要么修改事务aop方式为AnnotationAwareAspectJAutoProxyCreator,由于是通过注解实现的数据源切换aop,所以选择了后者解决方案,如下:

DataSourceConfig


@Bean
public AnnotationAwareAspectJAutoProxyCreator txProxy()
{
/*
 * 必须使用AspectJ方式的AutoProxy,这样才能和DataSourceSwitchAspect保持统一的aop拦截方式,否则不同的拦截方式会导致order失效
 */
AnnotationAwareAspectJAutoProxyCreator c = new AnnotationAwareAspectJAutoProxyCreator();
c.setInterceptorNames("txAdvice");
c.setIncludePatterns(Arrays.asList("execution (public com.etu..*Service(..))"));
c.setProxyTargetClass(true);
c.setOrder(2);
return c;
}

来源:https://my.oschina.net/u/2333620/blog/1805869

标签:Spring,声明式事务,@Aspect,拦截
0
投稿

猜你喜欢

  • 解决mybatis #{}无法自动添加引号的错误

    2023-09-21 11:45:02
  • Android使用onCreateOptionsMenu()创建菜单Menu的方法详解

    2023-05-13 06:21:01
  • Android Studio实现登录界面功能

    2023-06-11 20:27:35
  • 基于android中权限的集合汇总

    2023-04-06 09:32:35
  • C#中using语句的用法

    2023-07-02 05:33:24
  • Android开发中如何解决Fragment +Viewpager滑动页面重复加载的问题

    2023-12-24 20:21:25
  • unity 如何使用LineRenderer 动态划线

    2021-10-27 03:42:50
  • Java NIO实战之多人聊天室

    2022-02-28 15:05:00
  • C#实现在Form里面内嵌dos窗体的方法

    2022-04-27 07:13:07
  • java_object的简单使用详解

    2023-08-22 11:35:57
  • 浅谈Android Studio如何Debug对应so文件C/C++代码

    2023-11-20 03:23:35
  • Android中Button实现点击换图案及颜色

    2022-06-28 00:42:10
  • C语言 超详细总结讲解二叉树的概念与使用

    2023-11-08 20:24:56
  • C#中 MessageBox的使用技巧

    2023-06-25 16:15:48
  • Android Dialog 动画实例详解

    2022-10-22 22:24:29
  • SpringBoot项目如何打war包问题详解

    2023-06-07 08:33:47
  • SpringBoot2使用Jetty容器操作(替换默认Tomcat)

    2023-11-24 01:17:15
  • Android利用传感器仿微信摇一摇功能

    2022-09-10 18:18:18
  • Java8新特性Stream流实例详解

    2023-05-04 12:55:05
  • Android判断网络状态的代码

    2022-08-17 08:01:15
  • asp之家 软件编程 m.aspxhome.com