MyBatis源码解析之Mapper方法调用过程
在此声明,此文章是对江荣波老师的《MyBatis3源码深度解析》的总结,尊重原作者。
分析过程
这里我们介绍Mapper方法的执行过程以及Mapper接口与Mapper SQL配置是如何关联的。
-
首先我们需要调用SqlSession对象的getMapper()获取一个动态代理对象MapperProxy,然后通过代理对象调用方法即可。
// MapperRegistry类,根据Mapper接口Class对象获取Mapper动态代理对象 @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."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } //测试类 @Test public void testMybatis () throws IOException { // 获取配置文件输入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 通过SqlSessionFactoryBuilder的build()方法创建SqlSessionFactory实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 调用openSession()方法创建SqlSession实例 SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取UserMapper代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 执行Mapper方法,获取执行结果 List<UserEntity> userList = userMapper.listAllUser(); /* // 兼容Ibatis,通过Mapper Id执行SQL操作 List<UserEntity> userList = sqlSession.selectList( "com.blog4java.mybatis.com.blog4java.mybatis.example.mapper.UserMapper.listAllUser"); */ System.out.println(JSON.toJSONString(userList)); }
-
MapperProxy是一个动态代理对象,实现了InvocationHandler接口,用于实现动态代理相关逻辑。当我们调用动态代理对象的方法时,会执行MapperProxy的invoke()方法。
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 从Object类继承的方法不做处理 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); } // 对Mapper接口中定义的方法进行封装,生成MapperMethod对象 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }
-
在invoke()方法中,对Mapper接口定义的方法,调用cachedMapperMethod()方法获取一个MapperMethod对象,这里用到了设计模式的享元模式思想,首先从缓存中获取一个需要的对象,没有的话就创建一个,然后加入到缓存中。
private Mappe