org.springframeword.boot:spring-boot-starer-web: 2.0.4release
io.shardingsphere:sharding-jdbc-spring-boot-starter:3.0.0M3
org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1
com.alibaba:druid-spring-boot-starter:1.1.9
由于项目需要,走了一波sharding jdbc多数据源配置,算是实战演练了,此处记录下踩过的坑。
代码githut地址(https://github.com/autLory/test_sharding_pro),阉割版,去掉了与项目相关的东西,剩一些核心配置文件。
1,初始版本参考网上找各路大佬的博客资料写出来的,配置了两个数据源,然后在DataSourceConfig里面分别初始化,基本实现分库分表,主库的分表策略在配置文件里面配置,分库的分表策略是在DataSourceConfig文件里面初始化的时候配置手动写ShardingRuleConfiguration然后加到ShardingDataSource里面的(其实好一些的处理方法应该是都写在配置文件里面的,但是我没做出来)。两个DataSourceConfig文件分别初始化自己的数据源,mapper,xmlmapper,基本就完成了最初的版本。启动时的时候去除掉Spring boot自带的DataSourceAutoConfiguration文件。
2,初始版本完成之后,发现的第一个问题就是以前项目里面写的一个mybatis的拦截器失效了,拦截器的作用是拦截mybatis所有的insert ,update操作,添加一些业务字段,没改多数据源之前是正常使用的,改了之后发现失效了,然后debug模式启动发现拦截器确实是已经初始化过了,至于为什么没有生效,不知道。
解决思路:看源码了,先找到前面去除掉的DataSourceAutoConfiguration文件,看看源码,好像跟mybatis没什么关系,然后搜了下spring boot自动配置mybatis的初始化过程找到了MybatisAutoConfiguration文件,也就是mybatis的初始化配置文件,,AutoConfigAfter,字面理解执行于参数的class文件初始化之后,这个类里面有个构造函数如下
看起来好像找到一个跟拦截器有点关系的了,然后看看下面哪个地方被调用,如下:
在初始化SqlSessionFactory的时候会把拦截器添加到实例里面,对比自己的Config文件,少了这么一步,所以拦截器初始化了但是没有生效时因为没有添加到mybatis的实例里面。
对应的改一下自己的配置文件,把interceptor加进去,再启动测试,正常使用,搞定。
3 ,后续发现的第二个问题,druid的sql监控没有了。为啥没有了,不知道,继续找原因改呗。
第一个猜测,druid相关的配置没有生效, 又开始debug配置文件,发现了一个问题
此处DataSource初始化是直接调用DataSourceBuilder的.build方法初始化的,没有任何参数,好吧,再看看DataSourceBuilder的代码
这个地方会去获取DataSource的类型,然后结果拿到的就是HikariDataSource,鬼鬼,怪不得没sql监控了,初始化出来的DataSource压根就不是DruidDataSource,原因找到了,继续改了,怎么改了,先看sharding初始化DataSource的源码,实际上Sharding jdbc的DataSource初始化是根据配置文件里面type属性来的,代码在SpringBootConfiguration文件
这个地方在初始化DataSourceMap的时候会找到配置文件里面 sharding.jdbc.datasource.names值对应的数据源,然后配置对应属性
看代码会发现这给放主要会调用两个方法
一个是public static <T> T handle(final Environment environment, final String prefix, final Class<T> targetClass)方法
该方法作用是将当前environment下的配置文件里面前缀为prefix的属性转换为一个targetClass对象
代码里面就是将前面为sharding.jdbc.datasource.ds的属性转换为一个map对象
第二个方法为DataSource getDataSource(final String dataSourceClassName, final Map<String, Object> dataSourceProperties)
源码如下,
意思是先找到DataSource类型的class对象,然后循环前面获取到的map对象,利用反射找到每一个key对应的set方法,将value值作为set方法的参数赋值给实例化出来的对象,然后将这个对象返回给上层的DataSouce初始化方法。这就实现了根据配置文件类实例化不同类型的DataSource实例。
而实际上我这边是有问题的,项目确认使用druid连接池,所以我没有把这些方法都copy到自己代码里面,而是在自己的DataSourceConfig文件里面直接初始化一个DruidDataSource实例返回,初始化的时候直接读取配置文件的各个属性值赋值。改好之后再次启动测试,就可以正常启动druid的sql监控了。
以上!