MyBatis-3.4.2-源码分析18:XML解析之RoleMapper userMapper = sqlSession.getMapper(RoleMapper.class)
2017-04-08 00:00
579 查看
这一节,我们来获取mapper
那么,这里,其实就是生成了一个代理对象。
接下来,开始调用一个方法,本质是进入了代理对象内部
首先,会根据method生成一个key,根据这个key去查找之前解析xml的结果里,去查是否有找到结果
找到的话,就直接取出来了
好,到这里,我们就生成了1个MappedStatement对象了。
接下来,看执行了什么。
---------------接下来,处理
this.method = new MethodSignature(config, mapperInterface, method);
看细节
---最后终于生成了一个MapperMethod
好,我们终于有了1个真正的MapperMethod实例了。
接下来,开始触发这个方法,我们来看看如何触发的
首先生成一个BoundSql对象
真正触发executor的doQuery
所以,重点就是在各个SimpleExecutor,BatchExecutor,ReuseExecutor的方法里。
这个核心的部分放在下一节。
RoleMapper userMapper = sqlSession.getMapper(RoleMapper.class);
@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // 这里开始 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } // 找到了mapperProxyFactory try { // 调用这个方法生成实例 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
public T newInstance(SqlSession sqlSession) { //首先生成 final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); //生成代理 return newInstance(mapperProxy); }
@SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { //在这里生成代理 //按下不表 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
那么,这里,其实就是生成了一个代理对象。
Step completed: "thread=main", test.Test.business(), line=37 bci=17 37 RoleMapper userMapper = sqlSession.getMapper(RoleMapper.class); > main[1] print userMapper userMapper = "org.apache.ibatis.binding.MapperProxy@3f197a46"
接下来,开始调用一个方法,本质是进入了代理对象内部
Role role = userMapper.getRole(1L);
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 这里是用了JDK自身的反射机制 try { if (Object.class.equals(method.getDeclaringClass())) { // 一般不符合,不走这个分支 return method.invoke(this, args); } else if (isDefaultMethod(method)) { // 一般也不走这个分支 return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } //一般走这个分支 //先拿缓存方法 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }
首先,会根据method生成一个key,根据这个key去查找之前解析xml的结果里,去查是否有找到结果
public boolean hasStatement(String statementName, boolean validateIncompleteStatements) { // 看到这里了 if (validateIncompleteStatements) { // 看到这里了 buildAllStatements(); // 看到这里了 } // 看到这里了 return mappedStatements.containsKey(statementName); }
Step completed: "thread=main", org.apache.ibatis.session.Configuration.hasStatement(), line=786 bci=0 786 if (validateIncompleteStatements) { main[1] main[1] next > Step completed: "thread=main", org.apache.ibatis.session.Configuration.hasStatement(), line=787 bci=4 787 buildAllStatements(); main[1] next > Step completed: "thread=main", org.apache.ibatis.session.Configuration.hasStatement(), line=789 bci=8 789 return mappedStatements.containsKey(statementName); main[1] print mappedStatements mappedStatements = "{interfaces.RoleMapper.deleteUser=org.apache.ibatis.mapping.MappedStatement@50a638b5, interfaces.RoleMapper.getRole=org.apache.ibatis.mapping.MappedStatement@1817d444, insertUser=org.apache.ibatis.mapping.MappedStatement@6ca8564a, interfaces.RoleMapper.insertUser=org.apache.ibatis.mapping.MappedStatement@6ca8564a, getRole=org.apache.ibatis.mapping.MappedStatement@1817d444, deleteUser=org.apache.ibatis.mapping.MappedStatement@50a638b5, updateUser=org.apache.ibatis.mapping.MappedStatement@50b472aa, interfaces.RoleMapper.updateUser=org.apache.ibatis.mapping.MappedStatement@50b472aa}" main[1]
找到的话,就直接取出来了
Step completed: "thread=main", org.apache.ibatis.session.Configuration.getMappedStatement(), line=746 bci=18 746 return mappedStatements.get(id); main[1] step > Step completed: "thread=main", org.apache.ibatis.session.Configuration.getMappedStatement(), line=739 bci=6 739 return this.getMappedStatement(id, true); main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=218 bci=53 218 ms = configuration.getMappedStatement(statementName); main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=219 bci=55 219 } else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35 main[1] print ms ms = "org.apache.ibatis.mapping.MappedStatement@1817d444"
好,到这里,我们就生成了1个MappedStatement对象了。
接下来,看执行了什么。
} else { //走这个分支 name = ms.getId(); //取出type type = ms.getSqlCommandType(); if (type == SqlCommandType.UNKNOWN) { throw new BindingException("Unknown execution method for: " + name); } }
Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=233 bci=174 233 name = ms.getId(); main[1] sep Unrecognized command: 'sep'. Try help... main[1] step > Step completed: "thread=main", org.apache.ibatis.mapping.MappedStatement.getId(), line=210 bci=0 210 return id; main[1] main[1] main[1] print id id = "interfaces.RoleMapper.getRole" main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=233 bci=180 233 name = ms.getId(); main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=234 bci=183 234 type = ms.getSqlCommandType(); main[1] print name name = "interfaces.RoleMapper.getRole" main[1] step > Step completed: "thread=main", org.apache.ibatis.mapping.MappedStatement.getSqlCommandType(), line=198 bci=0 198 return sqlCommandType; main[1] print sqlCommandType sqlCommandType = "SELECT" main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=234 bci=189 234 type = ms.getSqlCommandType(); main[1] step > Step completed: "thread=main", org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(), line=235 bci=192 235 if (type == SqlCommandType.UNKNOWN) { main[1] print type type = "SELECT" main[1] print type.getClass() type.getClass() = "class org.apache.ibatis.mapping.SqlCommandType" main[1]
---------------接下来,处理
this.method = new MethodSignature(config, mapperInterface, method);
看细节
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) { // 构造返回类型 Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface); // if (resolvedReturnType instanceof Class<?>) { // 返回类型 this.returnType = (Class<?>) resolvedReturnType; // end } else if (resolvedReturnType instanceof ParameterizedType) { this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType(); } else { this.returnType = method.getReturnType(); } // 是否返回为空 this.returnsVoid = void.class.equals(this.returnType); // 返回结果是否为集合,数组 this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray()); // this.returnsCursor = Cursor.class.equals(this.returnType); //继续 this.mapKey = getMapKey(method); // this.returnsMap = (this.mapKey != null); //null this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class); //null this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class); //看到这里了 this.paramNameResolver = new ParamNameResolver(configuration, method); //end }
---最后终于生成了一个MapperMethod
private MapperMethod cachedMapperMethod(Method method) { // 这里开始 MapperMethod mapperMethod = methodCache.get(method); if (mapperMethod == null) { // 生成一个方法 mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); //生成以后,放到缓存里,是1个线程安全的map methodCache.put(method, mapperMethod); } return mapperMethod; //end }
好,我们终于有了1个真正的MapperMethod实例了。
// 一般走这个分支 // 先拿缓存方法 final MapperMethod mapperMethod = cachedMapperMethod(method); // 开始触发这个方法 return mapperMethod.execute(sqlSession, args); }
接下来,开始触发这个方法,我们来看看如何触发的
首先生成一个BoundSql对象
Step completed: "thread=main", org.apache.ibatis.builder.StaticSqlSource.getBoundSql(), line=46 bci=0 46 return new BoundSql(configuration, sql, parameterMappings, parameterObject); main[1] print sql sql = "select * from t_user where id=?" main[1] print parameterMappings parameterMappings = "[ParameterMapping{property='id', mode=IN, javaType=class java.lang.Integer, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}]" main[1] print parameterObject parameterObject = "1" main[1]
真正触发executor的doQuery
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 从数据库查询 List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { // 看到这里了 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(), line=338 bci=12 338 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); main[1] print localCache localCache = "org.apache.ibatis.cache.impl.PerpetualCache@c2f3a6f7" main[1] step > Step completed: "thread=main", org.apache.ibatis.executor.SimpleExecutor.doQuery(), line=59 bci=0 59 Statement stmt = null;
所以,重点就是在各个SimpleExecutor,BatchExecutor,ReuseExecutor的方法里。
这个核心的部分放在下一节。
相关文章推荐
- MyBatis-3.4.2-源码分析14:XML解析之sqlElement(context.evalNodes("/mapper/sql"))
- MyBatis-3.4.2-源码分析12:XML解析之mapperElement(root.evalNode("mappers"))
- MyBatis-3.4.2-源码分析17:XML解析之bindMapperForNamespace
- MyBatis-3.4.2-源码分析16:XML解析之SqlSessionFactory|SqlSession
- MyBatis-3.4.2-源码分析8:XML解析之environmentsElement(root.evalNode("environments"))
- MyBatis-3.4.2-源码分析15:XML解析之buildStatementFromContext(context.evalNodes(‘select|insert|update|delete’
- Mybatis工作机制源码分析—SqlSessionUtils.getSqlSession工作机制
- Mybatis3源码分析(三):解析mapper的xml配置文件
- mybatis源码学习之执行过程分析(2)——config.xml配置文件和mapper.xml映射文件解析过程
- MyBatis-3.4.2-源码分析7:解析XML之settingsElement(settings)
- MyBatis-3.4.2-源码分析2:解析XML之settingsAsProperties(root.evalNode("settings"))
- MyBatis-3.4.2-源码分析1:解析XML之propertiesElement(root.evalNode("properties"))
- Mybatis3源码分析(三):解析mapper的xml配置文件
- MyBatis-3.4.2-源码分析9:XML解析之databaseIdProviderElement(root.evalNode("databaseIdProvider"))
- sqlSession.getMapper(UserMapper.class)的使用方式
- MyBatis-3.4.2-源码分析4:解析XML之pluginElement(root.evalNode("plugins"))
- MyBatis-3.4.2-源码分析5:解析XML之objectFactoryElement(root.evalNode("objectFactory"))
- MyBatis-3.4.2-源码分析6:解析XML之objectWrapperFactoryElement & reflectorFactoryElement
- MyBatis-3.4.2-源码分析11:XML解析之environmentsElement+Druid的解析准备工作:整合Druid
- Mybatis3源码分析(13)-Sql解析执行-BoundSql的加载-2