自定义MyBatis插件实现原理
MyBatis对数据库的操作,通过其内部四个核心接口的对应实现类完成。四个核心接口如下:
Executor(执行器): 执行SQL的StatementHandler(SQL语法构建器): 构建SQL语句的ParameterHandler(参数处理器): 处理SQL语句的入参ResultSetHandler(结果集处理器): 处理SQL结果的 插件实现原理,就是通过动态代理,增强对应接口中方法。
自定义插件
实现:给每条SELECT查询语句添加一个特定条件(1 =1)
如:select * from t1 where id = 2 and 1=1
实现MyBatis插件接口Interceptor,并重写对应方法
package gk. springboot. preheat. plugin ;
import org. apache. ibatis. executor. statement. BaseStatementHandler ;
import org. apache. ibatis. executor. statement. RoutingStatementHandler ;
import org. apache. ibatis. executor. statement. StatementHandler ;
import org. apache. ibatis. mapping. BoundSql ;
import org. apache. ibatis. mapping. MappedStatement ;
import org. apache. ibatis. mapping. SqlCommandType ;
import org. apache. ibatis. plugin. * ;
import java. lang. reflect. Field ;
import java. sql. Connection ;
import java. util. Properties ;
@Intercepts ( {
@Signature ( type = StatementHandler . class , method = "prepare" , args = { Connection . class , Integer . class } ) ,
} )
public class TenantMyBatisPlugin implements Interceptor {
@Override
public Object intercept ( Invocation invocation) throws Throwable {
System . out. println ( "target对象 => " + invocation. getTarget ( ) ) ;
StatementHandler target = ( StatementHandler ) invocation. getTarget ( ) ;
Field delegateField = target. getClass ( ) . getDeclaredField ( "delegate" ) ;
delegateField. setAccessible ( true ) ;
Object delegateObject = delegateField. get ( target) ;
Class < ? > superclass = delegateObject. getClass ( ) . getSuperclass ( ) ;
Field mappedStatementField = superclass. getDeclaredField ( "mappedStatement" ) ;
mappedStatementField. setAccessible ( true ) ;
MappedStatement mappedStatementObject = ( MappedStatement ) mappedStatementField. get ( delegateObject) ;
if ( mappedStatementObject. getSqlCommandType ( ) == SqlCommandType . SELECT ) {
BoundSql boundSql = target. getBoundSql ( ) ;
String newSql = boundSql. getSql ( ) . replace ( ";" , "" ) ;
if ( newSql. contains ( "where" ) ) {
newSql += " and 1 = 1" ;
} else {
newSql += " where 1 = 1" ;
}
Field sqlField = boundSql. getClass ( ) . getDeclaredField ( "sql" ) ;
sqlField. setAccessible ( true ) ;
sqlField. set ( boundSql, newSql) ;
System . out. println ( "最终SQL => " + boundSql. getSql ( ) ) ;
}
return invocation. proceed ( ) ;
}
@Override
public Object plugin ( Object target) {
System . out. println ( "包装的目标对象 => " + target) ;
return Plugin . wrap ( target, this ) ;
}
@Override
public void setProperties ( Properties properties) {
System . out. println ( "插件初始化参数 => " + properties) ;
}
}
将自定义插件注入到MyBatis中去
package gk. springboot. preheat. config ;
import gk. springboot. preheat. plugin. TenantMyBatisPlugin ;
import org. mybatis. spring. boot. autoconfigure. ConfigurationCustomizer ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ;
@Configuration
public class MyBatisConfig {
public TenantMyBatisPlugin tenantMyBatisPlugin ( ) {
return new TenantMyBatisPlugin ( ) ;
}
@Bean
public ConfigurationCustomizer configurationCustomizer ( ) {
return configuration -> configuration. addInterceptor ( new TenantMyBatisPlugin ( ) ) ;
}
}
测试
测试SELECT语句是否添加了 1 =1 的where条件 测试UPDATE语句是否没有添加
参考文章