MyBatis源码分析

Mybatis一般按照分析来说,可以按照三步曲进行

1、xml解析对应的配置文件

2、将配置文件通过XMLConfigBuilder解析生成Configuration对象。

3、SqlSessionFactoryBuilder通过builder方法将Configuration对象存入到里面。

4、configuration委托给MapperRegistry:运用动态代理生成对应的Dao对象.然后拿到配置文件中对应的id的sql语句,利用SqlSession执行相应的操作。

 

一般面试会问mybatis的接口是怎么实现的,其原理就是用采用jdk的动态代理来实现的,只是它的接口并没有实现类,动态代理的invoke方法中得到当前的method方法去构造MapperMethod对象,看具体代码:

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

通过mapperregistry获取对应的对象,进一步看看getMapper的代码:

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的代理是接口的,并没有实现,不要忘记哦,来看看具体的代码:

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来执行增删查改。

posted @ 2017-10-25 09:05  杠上开花  阅读(151)  评论(0编辑  收藏  举报