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