定位:此篇尝试用另一种角度描述如何完成一个mybatis插件,全程可以按段落跳跃阅读,有任何不适欢迎指出Thanks♪(・ω・)ノ
为什么这么设计
如果我想实现一个orm增强插件,首先就应该避免硬编码,最好与业务代码无关。那么就要看看orm框架有没有什么拓展点了。
为了易用,配置越简单越好,要么引入外部配置中心,或者自定义ThreadLocal
读取配置。
符合上面这些的,不就是PageHelper
吗?
那么自己实现也就方便了,参考PageHelper
的思路就可以了
如何增强
这就不得不讲到责任链了,mybatis把所有插件插入到
org.apache.ibatis.session.Configuration#interceptorChain
中,等到时候得时候,就返回责任链,
想怎么增强,自己在interceptor
中实现即可。
简单配置
第三方配置就不多说了,自己实现即可。
这里参考下PageHelper
是通过ThreadLocal,判断上下文参数来判断是否可以跳过。
简单实现一个
gitee仓库地址:gitee.com/Nortyr/alli…
org.apache.ibatis.session.Configuration#interceptorChain
中@Configuration
@DependsOn("com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration")
public class SelfConfiguration {
@Autowired
private List sqlSessionFactoryList;
@PostConstruct
public void addPageInterceptor() {
SelfInteceptor interceptor=new SelfInteceptor();
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
}
Object obj=invocation.proceed();
都是业务增强代码,随便你怎么实现。我再这里主要完成了2个功能- 通过方法名+_SELF走一个自己的查询(完全没用,写着玩)
- 记录下总共pageHelper和sql执行的总共时间(完全没用,写着玩)
完全没有任何实质性的作用,就是写着玩,你们爱怎么实现怎么实现
@Intercepts(
{
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
}
)
public class SelfInteceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long start=System.currentTimeMillis();
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
ResultHandler resultHandler = (ResultHandler) args[3];
Executor executor = (Executor) invocation.getTarget();
RowBounds rowBounds = (RowBounds) args[2];
String msId = ms.getId();
Configuration configuration = ms.getConfiguration();
Page page = PageHelper.getLocalPage();
PageHelper.clearPage();
String countMsId = msId + "_SELF";
MappedStatement selfMs=configuration.getMappedStatement(countMsId, false);
Object countResultList = executor.query(selfMs, parameter,rowBounds, resultHandler);
System.out.println(countResultList);
Class clazz= PageMethod.class;
Method m1 = clazz.getDeclaredMethod("setLocalPage",Page.class);
m1.setAccessible(true);
m1.invoke(null,page);
//注:下面的方法可以根据自己的逻辑调用多次,在分页插件中,count 和 page 各调用了一次
Object obj=invocation.proceed();
long end=System.currentTimeMillis();
System.out.println("恭喜你成功浪费了5分钟。。。。"+(end-start));
return obj;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
总结
虽然写的很少,但是,PageHelper
的底层逻辑应该明白了,就是上面精细化实现没说了,这个应该有别的dalao写过文章了吧,我就懒得写了。再回顾下开篇的2个问题
- 如何增强
- 自定义插件加入到
interceptorChain
中即可,mybatis自己回生成责任链
- 自定义插件加入到
- 如何易用
PageHelper
是通过ThreadLocal
实现
gitee地址:gitee.com/Nortyr/alli…