mybatis的插件开发:主要就是实现拦截器,mybatis在创建四大神器的时候会将我们的拦截器逻辑通过代理的方式植入进去。
mybatis在创建Executor,StatmentHandler,ParameterHandler,ResultHandler这四个对象的时候都会有这个处理逻辑: interceptorChain.pluginAll(resultSetHandler)
下面看其中两个:
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
下面我们看看这个方法干了啥呢
public Object pluginAll(Object target) {
//遍历拦截器,然后执行拦截器的plugin方法,最后返回target对象
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
下面我们就实现一个简单拦截器,拦截sql语句,加上limit条件:
1.实现Interceptor接口
@Intercepts(value= {@Signature( //拦截Statmenthandler的prepare方法,这个方法需要参数的参数类型是Connection,Integer
type=StatementHandler.class,
method="prepare",
args= {Connection.class,Integer.class}
)})
public class CustomerInterceptor implements Interceptor{
Integer limitNum = null;
//拦截到的处理逻辑 相当于invoke方法
public Object intercept(Invocation invocation) throws Throwable {
Object prepareStatmentHandler = invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(prepareStatmentHandler);
//对应BaseStatmentHandler下的参数
Object param = metaObject.getValue("parameterHandler.parameterObject");
System.out.println("sql參數:"+param);
String sql = String.valueOf(metaObject.getValue("boundSql.sql"));
sql += " limit 0,"+limitNum;
metaObject.setValue("boundSql.sql", sql);
Object result = invocation.proceed();
return result;
}
//为target对象生成代理对象 相当于Proxy.newInstanceProxy(classLoader,interfaces,代理实现类)
public Object plugin(Object target) {
//Plugin 获取被@Intercepts注解的类,然后调用Proxy.newInstanceProxy生成代理
Object proxyObj = Plugin.wrap(target, this);
return proxyObj;
}
//为拦截器对象属性进行赋值
public void setProperties(Properties properties) {
limitNum = Integer.valueOf(properties.get("limitNum").toString());
}
}
2.在mybatis配置文件中配置拦截器
<plugins>
<plugin interceptor="stu.wf.interceptor.CustomerInterceptor">
<property name="limitNum" value="3"/>
</plugin>
</plugins>
这样在调用prepare预编译之前,就会进行拦截,然后拼接sql
大体的步骤就是这个样子.