MyBatis源碼分析

Mybatis通常按照分析來講,能夠按照三步曲進行面試

一、xml解析對應的配置文件sql

二、將配置文件經過XMLConfigBuilder解析生成Configuration對象。apache

三、SqlSessionFactoryBuilder經過builder方法將Configuration對象存入到裏面。mybatis

四、configuration委託給MapperRegistry:運用動態代理生成對應的Dao對象.而後拿到配置文件中對應的id的sql語句,利用SqlSession執行相應的操做。app

 

通常面試會問mybatis的接口是怎麼實現的,其原理就是用採用jdk的動態代理來實現的,只是它的接口並無實現類,動態代理的invoke方法中獲得當前的method方法去構造MapperMethod對象,看具體代碼: ui

public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return this.mapperRegistry.getMapper(type, sqlSession); }

經過mapperregistry獲取對應的對象,進一步看看getMapper的代碼:this

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if(mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

能夠看到,動態代理開始了,經過代理來產生對應的對象,可是mybatis的代理是接口的,並無實現,不要忘記哦,來看看具體的代碼:spa

protected T newInstance(MapperProxy<T> mapperProxy) {
    return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); //動態代理模式生成對應的類
}

public T newInstance(SqlSession sqlSession) {
    MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        if(Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }

        if(this.isDefaultMethod(method)) {
            return this.invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }
     //這裏去拿到對應的sql語句
    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    return mapperMethod.execute(this.sqlSession, args);
}

在來看看MapperMethod中的execute的方法:代理

public Object execute(SqlSession sqlSession, Object[] args) {
    Object param;
    Object result;
    switch(null.$SwitchMap$org$apache$ibatis$mapping$SqlCommandType[this.command.getType().ordinal()]) {
    case 1:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        break;
    case 2:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        break;
    case 3:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        break;
    case 4:
        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 if(this.method.returnsCursor()) {
            result = this.executeForCursor(sqlSession, args);
        } else {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = sqlSession.selectOne(this.command.getName(), param);
        }
        break;
    case 5:
        result = sqlSession.flushStatements();
        break;
    default:
        throw new BindingException("Unknown execution method for: " + this.command.getName());
    }

    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;
    }
}

能夠看到,最終仍是經過SqlSession來執行增刪查改。code

相關文章
相關標籤/搜索