在前几篇文章中我们按照PageHelper中对的调用层次依次分析,逐层查找,找到了PageInterceptor
拦截器,目前知道是其中的intercept(invocation)方法拦截了Executor.query的sql请求,但是仍然没有找到修改sql的代码是在哪里。
今天我们将揭晓这一重大问题。
接着上次阐述到的PageInterceptor
拦截器方法中调用了ExecutorUtil
的pageQuery方法,调用方式如下所示:
resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
在这个方法有一个重要的参数dialect
,这个是根据不同的数据库去动态匹配不同的实现类。那么它是在何处定义和绑定的呢?
我们在PageInterceptor
中查找它的定义:
private volatile Dialect dialect;
这其中有一个修饰符volaile
我们不展开讲(主要是我也不是很清楚)。
Dilect是一个接口,其注释中明确写明:数据库方言,针对不同数据库进行实现。我们来看看那其实合适进行绑定的。
在拦截器方法中第一次使用dialect
这个变量时,调用了一个方法:
checkDialectExists(); // 下述代码是拦截器中首次使用dialect //对 boundSql 的拦截处理 if (dialect instanceof BoundSqlInterceptor.Chain) { boundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.ORIGINAL, boundSql, cacheKey); }
我们来看一下这个checkDialectExists
方法:
/** * Spring bean 方式配置时,如果没有配置属性就不会执行下面的 setProperties 方法,就不会初始化 * <p> * 因此这里会出现 null 的情况 fixed #26 */ private void checkDialectExists() { if (dialect == null) { synchronized (default_dialect_class) { if (dialect == null) { setProperties(new Properties()); } } } }
通过其中的dialect == null
的两次判断,我们可以知道这个是执行dialect变量初始化的。其初始化方法是setnew Properties()
,我们继续来看这个方法以及Properties类。
@Override public void setProperties(Properties properties) { //缓存 count ms msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties); String dialectClass = properties.getProperty("dialect"); if (StringUtil.isEmpty(dialectClass)) { dialectClass = default_dialect_class; } try { Class<?> aClass = Class.forName(dialectClass); dialect = (Dialect) aClass.newInstance(); } catch (Exception e) { throw new PageException(e); } dialect.setProperties(properties); String countSuffix = properties.getProperty("countSuffix"); if (StringUtil.isNotEmpty(countSuffix)) { this.countSuffix = countSuffix; } }
我们最关心的还是dialect
对象,代码方法中的第二行就为我们指明了其会设置在配置文件的dialect参数中。我们反过来去查看最初若依项目的配置文件:
# PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql
为什么这里的参数dialect
与若依代码中的参数名helperDialect
不一致呢?
这是因为我们使用的spring-boot,使用的是springboot-pagehelper-starter
,在其项目代码中有:
public String getDialect() { return properties.getProperty("dialect"); } public void setDialect(String dialect) { properties.setProperty("dialect", dialect); } public String getHelperDialect() { return properties.getProperty("helperDialect"); } public void setHelperDialect(String helperDialect) { properties.setProperty("helperDialect", helperDialect); }