接口式编程原理(中)
SqlSession接口有两个实现类,分别为DefaultSqlSession和SqlSessionManager,这里获取的对象是属于DefaultSqlSession实现类的。
首先sqlSession是我们手动封装获取的,这里调用的是Mybatis的方法,然后通过SqlSessionFactory对象的OpernSession方法获取SqlSession,其中SqlSessionFactory接口也有两个实现类,分别为DefaultSqlSessionFactory和SqlSessionManager,由源码得知SqlSessionFactoryBuilder类提供了build(Reader reader),该方法返回的是SqlSessionFactoryBuilder类提供的build(Reader reader,String envirment,Properties properties),该方法又返回的是SqlSessionFactoryBuilder提供的build(Configuration config)方法,该方法最后返回的是DefaultSqlSessionFactory对象。所以SqlSessionFactory获取的是DefaultSqlSessionFactory实现类对象。所以openSession方法是属于DefaultSqlSessionFactory里的方法。该openSession方法返回的是DefaultSqlSessionFactory提供的openSessionFromDataSource(ExecutorType execType,..),该方法最终返回的是DefaultSqlSession类的对象
所以最终获取的是DefaultSqlSession。






这里我们可以查看DefaultSqlSession的getMapper方法,该方法返回的是Configuration类提供的getMapper方法,该方法第一个参数就是传进来的class,也就是接口的类类型,第二个参数是this,也就是方法的对象,也就是sqlSession,该方法返回的是MapperRegistry类提供的getMapper方法,该方法返回值可以理解为通过代理工厂,生产一个代理返回出去(这里就是前面说的通过动态代理创建实例)。



该动态工厂的由来是Map对象(以类类型作为Key,MapperProxyFactory作为Value)的get方法,该get方法中传入一个类类型,MapperRegistry类提供了addMapper方法,该方法需要传入一个类类型,然后用Map对象的input方法把传入的类类型作为key,临时创建一个动态工厂作为value,并传入这个类类型,只有调用了这个方法才会对Map集合初始化,该方法的调用是在加载Mybatis核心配置文件时进行调用的,它会不停的调用这个方法,为不同的Class创建代理工厂。



动态工厂创建代理对象是通过MapperProxyFactory的new Instance(SqlSession sqlSession)方法,该方法中创建了代理类,该代理类的构造函数中第一个参数是传进来的sqlSession,后两个参数是代理工厂的属性,第二个参数就是接口的类类型,构造函数并没有为其他属性赋值,所以第三个参数只是Map初始化的一个对象。


getMapper返回的对象实际上是一个Proxy.newProxyInstance返回的代理实例
MyBatis会加载mapper配置文件的namespace为一个Class<T>类型实例
接口式编程原理(中)
SqlSession接口有两个实现类,分别为DefaultSqlSession和SqlSessionManager,这里获取的对象是属于DefaultSqlSession实现类的。
首先sqlSession是我们手动封装获取的,这里调用的是Mybatis的方法,然后通过SqlSessionFactory对象的OpernSession方法获取SqlSession,其中SqlSessionFactory接口也有两个实现类,分别为DefaultSqlSessionFactory和SqlSessionManager,由源码得知SqlSessionFactoryBuilder类提供了build(Reader reader),该方法返回的是SqlSessionFactoryBuilder类提供的build(Reader reader,String envirment,Properties properties),该方法又返回的是SqlSessionFactoryBuilder提供的build(Configuration config)方法,该方法最后返回的是DefaultSqlSessionFactory对象。所以SqlSessionFactory获取的是DefaultSqlSessionFactory实现类对象。所以openSession方法是属于DefaultSqlSessionFactory里的方法。该openSession方法返回的是DefaultSqlSessionFactory提供的openSessionFromDataSource(ExecutorType execType,..),该方法最终返回的是DefaultSqlSession类的对象
所以最终获取的是DefaultSqlSession。






这里我们可以查看DefaultSqlSession的getMapper方法,该方法返回的是Configuration类提供的getMapper方法,该方法第一个参数就是传进来的class,也就是接口的类类型,第二个参数是this,也就是方法的对象,也就是sqlSession,该方法返回的是MapperRegistry类提供的getMapper方法,该方法返回值可以理解为通过代理工厂,生产一个代理返回出去(这里就是前面说的通过动态代理创建实例)。



该动态工厂的由来是Map对象(以类类型作为Key,MapperProxyFactory作为Value)的get方法,该get方法中传入一个类类型,MapperRegistry类提供了addMapper方法,该方法需要传入一个类类型,然后用Map对象的input方法把传入的类类型作为key,临时创建一个动态工厂作为value,并传入这个类类型,只有调用了这个方法才会对Map集合初始化,该方法的调用是在加载Mybatis核心配置文件时进行调用的,它会不停的调用这个方法,为不同的Class创建代理工厂。



动态工厂创建代理对象是通过MapperProxyFactory的new Instance(SqlSession sqlSession)方法,该方法中创建了代理类,该代理类的构造函数中第一个参数是传进来的sqlSession,后两个参数是代理工厂的属性,第二个参数就是接口的类类型,构造函数并没有为其他属性赋值,所以第三个参数只是Map初始化的一个对象。


查看一个接口的所有实现类:选中接口名,Ctrl+T 或者选中该接口名,按F4,即 Open Type Hierarchy IMessage imessage=sqlSession.getMapper(IMessage.class);//获取到的就是代理实例 messageList =imessage.queryMessageList(parameter);//代理实例执行接口方法时,就会触发调用处理程序,也就是第三个参数对象的invoke()方法,MapperProxy是实现了InvocationHandler接口的 MapperProxyFactory.newInstance(MapperProxy<T> mapperProxy){ --return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader()//通过接口获取类加载器,new Class[]{mapperInterface}//代理类实现的接口数组,mapperProxy//调用代理实例的处理程序) --} 解决了三个问题: 1、为什么只定义了一个接口,没有实现类的情况下,接口方法可以被调用,因为动态代理。 2、为什么sqlSession.getMapper(.class)可以根据传入的参数,返回一个对应的类型,因为泛型。 3、Mybatis加载文件时,利用namespace加载了一个class,然后把这个class与代码中传入接口的class进行匹配,方法执行所需要的信息就是来自于已经匹配成功的配置文件中,当结果与配置文件对应上后,调用接口的方法执行sql语句。