mybatis-plus sql注入原理(3.0.1)

MP版本为3.0.1

sql注入原理

①,入口类 com.baomidou.mybatisplus.core.injector.AbstractSqlInjector ,重点是这个方法

  public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
        String className = mapperClass.toString();
        Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
        if (!mapperRegistryCache.contains(className)) {
            List<AbstractMethod> methodList = this.getMethodList();
            Assert.notEmpty(methodList, "No effective injection method was found.");
            // 循环注入自定义方法,这里开始注入sql
            methodList.forEach(m -> m.inject(builderAssistant, mapperClass));
            mapperRegistryCache.add(className);
            /**
             * 初始化 SQL 解析
             */
            if (GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration()).isSqlParserCache()) {
                SqlParserHelper.initSqlParserInfoCache(mapperClass);
            }
        }
    }

②,由AbstractMethod 的injectMappedStatement 方法完成具体的注入,

我们看到实际是有其实现类的一个个injectMappedStatement 来完成注入的

ceecdbc199d8a8f163cfe92122d31428871.jpg

③,这里我以DeleteById 为例

  @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        //得到待解析sql的模板
        SqlMethod sqlMethod = SqlMethod.DELETE_BY_ID;
        //利用语言驱动和配置信息,table元数据,和刚才得到的sql方法模板得到sqlSource
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, String.format(sqlMethod.getSql(),
            tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty()), modelClass);
        //最后添加到mybatis的configuration里的mappedStatements中

        return this.addDeleteMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource);
    }

④,DELETE_BY_ID的模板如下

由此我们可以猜出,在tableInfo 中必须要能得出表名和该表主键

7493f5de18dd1838ddef6f637e323cd154a.jpg

执行AbstractSqlInjector #inspectInject 的原理

我们可以在该方法的第一行打一个断点

3a24a1c06a49cb8318052a3c8c79e23c4b7.jpg

看我红框圈起来的部门,我们可以大致猜出,是spring容器在实例化组件时,在实例化组件后调用组件的初始化方法,而引起的一连串反应。

通过翻看源码,我大致解释一下

1,AbstractAutowireCapableBeanFactory调用组件的afterPropertiesSet方法,这个组件的beanName为userMapper,这是一个我定义的一个继承自BaseMapper的一个接口

1d2df03caa16a3c328c7e1a94a8b5a7b9c0.jpg

2,不知怎么地,居然跑去调用 DaoSupport的afterPropertiesSet方法(知道的朋友欢迎留言)

84bd9cace55ead41f1a2d00571899b5efb2.jpg

3,然后调用到了其子类的MapperFactoryBean 的checkDaoConfig方法

重点是一行,这个configuration是继承自org.apache.ibatis.session.Configuration 的子类,是有mp自定义的一个类

configuration.addMapper(this.mapperInterface);

672d5bbb6accc9ccbba6dd461554d1dc020.jpg

4,接下来调用com.baomidou.mybatisplus.core.MybatisMapperRegistry的addMapper方法

断点停在了86行

b17a81dcc2232e2788ac9ad74e8751f2abc.jpg

5,我们看这个parse方法

利用GlobalConfigUtils 得到ISqlInjector,然后调用其inspectInject方法

27625239c7f34befc6512126ff067b78e4b.jpg

6,我们看看mp是如何得到这个ISqlInjector的

   public static ISqlInjector getSqlInjector(Configuration configuration) {
        // fix #140
        GlobalConfig globalConfiguration = getGlobalConfig(configuration);
        //从配置里拿,如果有,则用配置的
        ISqlInjector sqlInjector = globalConfiguration.getSqlInjector();
        if (sqlInjector == null) {
            //没有配置,默认给一个DefaultSqlInjector
            sqlInjector = new DefaultSqlInjector();
            globalConfiguration.setSqlInjector(sqlInjector);
        }
        return sqlInjector;
    }

7,而 DefaultSqlInjector 是继承自 AbstractSqlInjector 类的

由于DefaultSqlInjector没有重写AbstractSqlInjector的inspectInject方法,

所以DefaultSqlInjector在调用inspectInject方法时,实际上会用父类AbstractSqlInjector的inspectInject方法。

转载于:https://my.oschina.net/u/3574106/blog/2222591

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值