背景
mirai-console
最近在学习写mirai console插件,mirai本身是kotlin开发,对于我真是既友好又不友好…不友好的是kotlin真的太抽象了,阅读起来有一定障碍,友好的是有问题至少能用java填坑..
数据存储
mirai console提供的数据存储PluginData 本身算是为kotlin设计的,java使用有些不便(而且虽然已经在计划中,但目前还不支持数据库存储)。数据的存储 以及一些查询等等…我觉得还是数据库更胜一筹的,于是乎还得整合数据库(当然为了插件的便捷性,数据库依然是sqlite)
mybatis
为什么是mybatis不是jpa,不是hibernate?sql归sql,代码归代码,这是我喜欢mybatis的原因。另一个主要原因是:用惯了…
无spring
其实在准备写此插件之前,已经写过一个mirai+spring的项目了WMagicBotR,那个项目就是 spring+sqlite+mybtis,不得不说spring确实是为开发人员省下很多心,特别是springboot 一键搞定。
然而这些便利是有代价的:
- 打包后jar体积庞大(可以通过阉割spring解决)
- 不熟悉的kotlin+不熟悉的构建工具gradle,使得一开始使用springboot的过程中,打包后的jar要不打包失败,要不打包后无法被识别为插件很是心累…
springboot默认需要一个main方法启动类,而作为mirai console插件,他本身是不该主动启动的,应该在插件被加载的时候才启动。这里就有一个问题需要想明白,这个项目是spring作主还是mirai做主?上一个项目其实是spring做主的,使用mirai获得的bot对象作为一个bean被spring管理着,哪里需要bot在哪里注入就行。但是作为console插件,整个环境下不应该有bot对象,而是通过mcl等其他mirai前端来调用插件的方法,调用者(bot)是不固定的。
失去了 在任意地方获取bot对象 整个需求后,作为一个功能性插件,对于spring的需求也便弱化了…
需求与坑
现在总结一下需要做的事,非spring+mybatis+sqlite,这里面还有一些隐藏的小问题(坑),比如说:
- mybatis+sqlite,sqlite文件存放的位置不是固定的url,这就不该使用常规的mybatis-config.xml配置文件了
- mapper的注册方式有4种,package,url,class,resource用哪一种?为了可以让mapper.xml一家人整整齐齐的待在resourses文件夹下,得用resource模式
- 可惜 不用config.xml配置文件的方式…貌似不能用resource注册mapper
- 开发环境的resource,和打成jar包的resource,他一样吗?
几个问题一环扣一环..接下来就开始一点点解决吧
正文
相关详细代码会在本文最后贴出,源码见WMagicBotRP
sqlite数据初始化
数据初始化的流程比较好理解,检查数据文件是否存在,如果不存在则创建文件。这边就不用mybatis了,为什么呢?如果没有初始化的话,db文件都不存在,相当于mybatis没有数据库连接的url
1 | // 初始化数据文件 |
mybatis的配置
先看看config.xml
上面提过,因为需要动态的获取db文件的地址,这里的配置就不再使用mybatis-config.xml文件了,但是原理是差不多的。所以先来看一下使用配置文件的方式
1 | // mybatis官方提供的配置 |
创建Configuration
可以看到最外层标签configuration下包含environments以及mappers注册,其中environments中指定了数据源dataSource和事务管理transactionManager。照猫画虎,先手动构建configuration
1 | // 先构建Configuration对象 |
第十行,设置transactionFactory的时候,有2种选择JdbcTransactionFactory 以及ManagedTransactionFactory,这就对应了xml配置文件中的 type=”JDBC” 和 type=”MANAGED”,前者的事物由connection对象的具体方法控制,后者则是把事物交给了容器(tomcat,weblogic,grassfish等),作为插件,我们选择JDBC
mapper的注册
在需求与坑那部分,提到需要使用resource方式来注册mapper,但是…麻烦来了,在Configuration中提供的mapper注册方式里,没有resource模式
1 | // Configuration 提供的方式,可以看到是class模式和package模式 |
这就产生了一点小小的困难,不过没有提供不代表没办法注册,他自己是怎么注册的呢?去Configuration源码中看看
1 | // 使用配置文件build调用的方法 |
可以看到第8行使用了XMLConfigBuilder去解析获取的xml文件,在跟着进去找找,在文件靠下方可以找到以下代码
1 | private void mapperElement(XNode parent) throws Exception { |
这熟悉的package、resource、url、class让人振奋,这段代码中12-16行正是我们所需要的,到此解决了Configuration没有提供resource注册方式的麻烦(有兴趣可以深入再看看)
1 | // 我们把找到的代码封装为一个方法 注册xml mapper |
mapper的扫描
单个mapper已经可以注册,接下来将我们需要的mapper作为参数导入即可完成注册。这没有什么难度,mapper统一存放在项目的resources资源mapper目录下,获取mapper所有的文件即可
1 | public static List<String> getFileXmlRes() { |
到这里一切都很顺利,运行测试已经通过,然而打包后就出现了一些小小的问题…上面遍历的方法是基于文件系统的。而打包后所有的文件都在jar包内部,资源文件不再属于文件系统,只能指定资源名称将资源作为流读取出来,无法做到遍历获取。
这时候就得针对jar包来做一个专门的读取资源文件
1 | public static List<String> getJarXmlRes() { |
实际情况下根据运行环境的不同,应该使用对应的读取方式。针对这个做一下优化,就完成了
1 | private static void magicMapperLoader(Configuration configuration) { |
SqlSession的获取
1 | // datasource,enviroment等配置 |
获取session的时候要注意一下:autocommit参数默认是false的,不想每次执行完sql自己commit的话,还是设置为自动commit比较方便一些,当然这属于仁者见仁智者见智。
使用mybatis
具体的mapper接口和xml文件就不具体说明了,有没有spring都一样,该怎么写怎么写。就简单说一下没有@Autowised 如何使用定义的接口
1 | // mapper接口,对应的xml就不写了大家都懂 |
结语
框架真是带来了很多便利,那么,代价是什么呢?
附代码
更多请见WMagicBotRP
1 | import org.apache.ibatis.builder.xml.XMLMapperBuilder; |