mybatisソース解析(四)-mapperメソッド呼び出しプロセス


mybatisソースコード解析(一)-冒頭mybatisソースコード解析(二)-ロードプロセスmybatisソースコード解析(三)-SqlSession.selectOne類似メソッド呼び出しプロシージャmybatisソース解析(4)-mapperメソッド呼び出しプロシージャmybatisソース解析(5)-mybatisがどのように実装するトランザクション制御mybatisソース解析(6)-spring-txと協力してトランザクションを実装する原理mybatisソース解析(7)-mybatis一級キャッシュがspringに遭遇した場合
転載は出典を明記してください.http://blog.csdn.net/bingospunky/article/details/79220894本文は馬彬彬のブログから
前のブログでは、SqlSessionの実行手順について説明しています.しかし、mybatisを使用する場合、一般的にMapperを使用して添削を行います.この文章では、Mapperの方法がどのように実行されているかを示します.Mapperを用いた添削改査は2つのステップに分けられ,第1ステップではまずMapperオブジェクトを取得し,第2部ではMapperメソッドを呼び出す.我々が呼び出したメソッドに対応するxxxMapper.xmlの内容は次のとおりです.
Code 1
    <select id="selectById" resultMap="baseResultMap">
        select
        "baseColumnList"/>
        from
        table1
        where id = #{id}
    select>

取得Mapper
取得Mapperの主なコードは次のとおりです.
Code 2 org.apache.ibatis.binding.MapperProxyFactory
    public T newInstance(SqlSession sqlSession) {
        MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); 
    }

このコードはMapperProxyFactoryのもので、MapperProxyFactoryの役割はMapperを生成し、1つのMapperが1つのMapperProxyFactoryに対応することです.コードから、私たちが取得したオブジェクトはJdbcProxyによって生成され、エージェントオブジェクトに必要な3つのパラメータが表示されます.1つ目は説明しません.2つ目は私たちが取得するMappeインタフェースです.3番目のパラメータmapperProxyは重要です.それはコールバックです.Mapperインタフェースのメソッドを呼び出すと、mapperProxyのメソッドがコールバックされます.mapperProxyでコールバックメソッドを実装し、データベースを操作する必要があります.mapperProxyについては、クエリー・プロシージャの実行について詳しく説明します.
マッパーを呼び出す方法
取得したMapperオブジェクトはJdbcProxyオブジェクトであるため、メソッドを呼び出すとコールバックインタフェースのメソッドが呼び出されます.コールバックインタフェースのコードは次のとおりです.
Code 3 org.apache.ibatis.binding.MapperProxy
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            return mapperMethod.execute(this.sqlSession, args);
        }
    }
    private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
        if (mapperMethod == null) {
            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
            this.methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
    }

9行目はMethodでMapperMethodを取得し、10行目はMapperMethodを呼び出す.executeメソッドは、後で本物のsqlを実行します.MapperMethodを取得する場合、最初に取得する場合は、MapperMethodを構築する必要があります.次に、MapperMethodを構築し、MapperMethodを実行します.executeの2つの部分について説明します.
MapperMethodの作成
MapperMethodを構築するコードは次のとおりです.
Code 4 org.apache.ibatis.binding.MapperMethod
    public MapperMethod(Class> mapperInterface, Method method, Configuration config) {
        this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
        this.method = new MapperMethod.MethodSignature(config, method);
    }

MapperMethod.SqlCommandは比較的簡単で、このMapperメソッドに対応するMappedStatementのIdとそのメソッドに対応するSqlCommandTypeを含み、SqlCommandTypeにはUNKNOWN,INSERT,UPDATE,DELETE,SELECT,FLUSHのいくつかの値がある.ここで、このMapperメソッドに対応するMappedStatementがない場合、org.apache.ibatis.annotations.Flush注記タグの場合、異常が放出されます.これはよく理解できます.xxxMapperです.xmlには対応する構成がなく,この方法はすべて実行できない.
MapperMethod.MethodSignatureは少し面倒で、MapperMethodを構築します.MethodSignatureのコードは次のとおりです.
Code 5 org.apache.ibatis.binding.MapperMethod.MethodSignature
    public MethodSignature(Configuration configuration, Method method) {
        this.returnType = method.getReturnType();
        this.returnsVoid = Void.TYPE.equals(this.returnType);
        this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
        this.mapKey = this.getMapKey(method);
        this.returnsMap = this.mapKey != null;
        this.hasNamedParameters = this.hasNamedParams(method);
        this.rowBoundsIndex = this.getUniqueParamIndex(method, RowBounds.class);
        this.resultHandlerIndex = this.getUniqueParamIndex(method, ResultHandler.class);
        this.params = Collections.unmodifiableSortedMap(this.getParams(method, this.hasNamedParameters));
    }

2行目でMapperを取得するメソッドの戻り値のタイプ.4行目は、配列やCollectionインタフェースが集合であるなど、戻りタイプが集合であるかどうかを取得します.この値は後で分析されます.7行目は、この方法のパラメータにorgが含むか否かを判断する.apache.ibatis.annotations.Param注記、この値は実パラメータの処理に影響します.8行目は、パラメータのRowBoundsタイプの位置を取得します.パラメータに複数のRowBoundsタイプのパラメータが含まれている場合は、例外も放出されます.9行目は8行目と同様にResultHandlerタイプパラメータの位置を取得します.10行目はすごいSortedMapを生成します
MapperMethodを実行します.execute
MapperMethod.executeのコードは次のとおりです.
Code 6 org.apache.ibatis.binding.MapperMethod
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        if (SqlCommandType.INSERT == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        } else if (SqlCommandType.UPDATE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        } else if (SqlCommandType.DELETE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        } else if (SqlCommandType.SELECT == this.command.getType()) {
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
        } else {
            if (SqlCommandType.FLUSH != this.command.getType()) {
                throw new BindingException("Unknown execution method for: " + this.command.getName());
            }
            result = sqlSession.flushStatements();
        }
        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }

コードは異なる状況に対して異なる処理を行うことができず、すべての状況をinsert、delete、update、select、flustに分け、selectでは、戻り値をどのように処理するかによって、それぞれカスタムResultHandler処理、戻りオブジェクトセット、戻りMap、単一オブジェクトを返す.次にflustの状況については議論しません.23行目に見えるorgが呼び出された.apache.ibatis.session.SqlSession.selectOneメソッドはデータベースを操作します.orgについてapache.ibatis.session.SqlSession.selectOneメソッドの類似メソッドがどのように実行されるかは、前のブログを参照してください.他の場合、彼らはorgを呼び出した.apache.ibatis.session.SqlSessionの方法は、2つの点があります:1、適切なorgを選択します.apache.ibatis.session.SqlSessionメソッドが呼び出されます.2.Mapperメソッドが伝達するパラメータをorgに変換する.apache.ibatis.session.SqlSession対応メソッドでサポートされているパラメータ.知ってるよapache.ibatis.session.SqlSessionのパラメータは1つだけで、単一のオブジェクトであるか、集合であるか、Mapであるか、二私たちがMapperメソッドを呼び出したときに渡されたのは複数のパラメータであり、JdbcProxyでは配列形式で保存されているので、パラメータの変換を行います.パラメータ変換呼び出しは、次のようなコードを持つメソッドです.
Code 7 org.apache.ibatis.binding.MapperMethod
    public Object convertArgsToSqlCommandParam(Object[] args) {
        int paramCount = this.params.size();
        if (args != null && paramCount != 0) {
            if (!this.hasNamedParameters && paramCount == 1) {
                return args[((Integer)this.params.keySet().iterator().next()).intValue()];
            } else {
                Map<String, Object> param = new MapperMethod.ParamMap();
                int i = 0;
                for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) {
                    EntryString> entry = (Entry)i$.next();
                    param.put(entry.getValue(), args[((Integer)entry.getKey()).intValue()]);
                    String genericParamName = "param" + String.valueOf(i + 1);
                    if (!param.containsKey(genericParamName)) {
                        param.put(genericParamName, args[((Integer)entry.getKey()).intValue()]);
                    }
                }
                return param;
            }
        } else {
            return null;
        }
    }

5行目、パラメータが1つしかない場合、パラメータにorgがない.apache.ibatis.annotations.Param注記では,配列の配列の最初の値を返し,Mapperメソッドを呼び出す最初の値でもある.他の場合はMapに戻ります.Mapを構築する際には,本ブログで前述したSortedMapを用いた.SortedMapの各位置について、この位置のkeyはシーケンス番号であり、valueはorgである.apache.ibatis.annotations.Param注記の値(シーケンス番号の文字列形式でない場合)は、キー値ペアの形式に変換する必要があります.キー値ペアのkeyはxxxMapperである必要があります.xmlの値を取るkeyはorgであるべきである.apache.ibatis.annotations.Param注記の値(シーケンス番号の文字列形式でない場合)は、ちょうどSortedMapのvalueです.キー値ペアのvalueは,我々がMapperメソッドを呼び出して伝達したパラメータの対応する位置の値であるべきである.11行目のコードはこのようにします.
最後に
濃縮:
Mapperメソッドの実行手順:JdbcProxyプロキシオブジェクトであるMapperオブジェクトを取得します.エージェントオブジェクトコールバックインタフェースでは、Methodに従ってorgが実行する.apache.ibatis.session.SqlSession対応の方法は,同時にパラメータの変換を完了する必要がある.