mybatis-plus sql注入原理(3.0.1)

MP版本爲3.0.1java

sql注入原理

①,入口類 com.baomidou.mybatisplus.core.injector.AbstractSqlInjector ,重點是這個方法spring

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 方法完成具體的注入,sql

咱們看到實際是有其實現類的一個個injectMappedStatement 來完成注入的apache

③,這裏我以DeleteById 爲例session

@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的模板以下mybatis

由此咱們能夠猜出,在tableInfo 中必需要能得出表名和該表主鍵app

執行AbstractSqlInjector #inspectInject 的原理

咱們能夠在該方法的第一行打一個斷點ide

看我紅框圈起來的部門,咱們能夠大體猜出,是spring容器在實例化組件時,在實例化組件後調用組件的初始化方法,而引發的一連串反應。ui

經過翻看源碼,我大體解釋一下this

1,AbstractAutowireCapableBeanFactory調用組件的afterPropertiesSet方法,這個組件的beanName爲userMapper,這是一個我定義的一個繼承自BaseMapper的一個接口

2,不知怎麼地,竟然跑去調用 DaoSupport的afterPropertiesSet方法(知道的朋友歡迎留言)

3,而後調用到了其子類的MapperFactoryBean 的checkDaoConfig方法

重點是一行,這個configuration是繼承自org.apache.ibatis.session.Configuration 的子類,是有mp自定義的一個類

configuration.addMapper(this.mapperInterface);

4,接下來調用com.baomidou.mybatisplus.core.MybatisMapperRegistry的addMapper方法

斷點停在了86行

5,咱們看這個parse方法

利用GlobalConfigUtils 獲得ISqlInjector,而後調用其inspectInject方法

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方法。

相關文章
相關標籤/搜索