问题产生背景:

在开发一个sdk的时候,里面会用到mybatis的拦截器对数据库返回的数据进行相关的处理,公司另一个团队的系统需要接入sdk,但是接入的时候发现,该系统本身也有对mybatis拦截器对处理,而且也是处理sql的返回数据,这样导致插件sdk用原来的方式获取sql的时候就会出现异常。

sdk的拦截器:

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_mybatis

sdk自定义拦截器的intercepter中会对返回的resulSettHandler处理

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_java_02

 首先需要拿到当前请求的sql:

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_sql_03

按照这种方式是可以拿到sql的。

正常情况下是这样的:

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_spring_04

也就是可以拿到具体的Sql的。

但是由于sdk中有mybatis的拦截器,接入系统也有mybatis的拦截器,且也是对返回的resultSetHandler进行处理。

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_java_05

 

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_数据库_06

 

这就导致了在获取sql的时候出现异常 

java.lang.NoSuchFieldException: boundSql
	at java.lang.Class.getDeclaredField(Class.java:2070)

debug的时候,发现,这个时候的target获取后并不是一个具体的resultsethandler对象,而是一个proxy的plugin,点开h后才能看到具体想要的那些,

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_sql_07

这样就获取不到sql了。

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_sql_08

 

经debug发现,在添加拦截器的时候

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_mybatis_09

 

如果是处理同一个的话,就会进行第二次代理,这样就导致我们在取sql的时候,拿出来的是一个代理plugin。

经过观察, 系统自定义的拦截器总是在sdk拦截器后执行,然后我把取sql的代码从sdk放到系统自定义的拦截器里面,发现可以正常渠道sql,也就是说,如果把sdk的拦截器执行顺序放到系统自定义的后面,那应该也可以,试验后发现,是可以的。

那么接下来就是调整两个拦截器执行顺序的问题了,两个方法:

1.xml文件配置

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_mybatis_10

在xml文件中配置两个拦截器,配置在前面的后执行,配置在后面的先执行。 

2.代码中添加

因为sdk不可能为这样一个系统专门改造,且sdk的拦截器是自动添加到sqlSession里面的,之前系统中的拦截器也是自动添加的,这时候添加顺序是先添加系统的,然后添加sdk的,现在改个顺序,让系统自带的变为手动添加。

首先去掉系统自带的拦截器的注解:

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_spring_11

然后手动添加:

springboot mybatis 拦截器获取表名 mybatis拦截器顺序_spring_12

 这样sdk的拦截器就变为后执行,能够正常获取sql。

成功解决问题。