一. Mybatis的核心对象 如何与SqlSession建立的联系?
我们现在使用Mybtais都是使用SqlSession.getMapper(xx)的形式,但是在之前Mybatis是由SqlSession.方法(namespace.id)的形式进行使用的,例如
SqlSession.insert()
SqlSession.update()
SqlSession.delete()等等
具体如下图所示,其中两个语法查询的结果都是一样的。
首先先给出一个结论,其实我们目前常用的形式,是Mybatis在之后更新的结果,但是在底层其实也是调用了SqlSession.方法(namespaec.id)[第二种格式]。
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
当我们使用这行代码的时候,我们有没有想过这样的问题??
EmpMapper是接口类型,这条语句肯定是将EmpMapper的实现类赋值给了empMapper,使用了java的多态形式。
那我们有没有想过:
1.EmpMapper的实现类在那里?
这个问题,我们直接给出答案,其实是使用了动态字节码技术,在JVM 运行时创建,在JVM运行结束后,消失啦。
2.如何创建EmpMapper的实现类呢?
使用了代理 (动态代理)的方法
补充:使用代理的几种情况
a. 为原始对象(目标)增加【额外功能】
b. 远程代理 1.网络通信 2.输出传输 (RPC)Dubbo
c. 接口实现类,我们看不见实实在在的类文件,但是运行时却能体现出来。
无中生有
其实是使用JDK的动态代理(基于接口的形式),目前先大概了解,在后面我们将自己实现一下动态代理,将第二种形式和第一种形式联系起来。
3.实现类如何进行实现的
对于这个,我们可以结合前面,可以得到这样的理解
interface EmpMapper {
List<Emp> getAllEmp();
int save(Emp emp);
}
通过动态代理 我们得到的实现类应该是这个样子
EmpMapperImpl implements EmpMapper {
List<Emp> getAllEmp(){
sqlSession.selectlist(namespace.id)
接下来就是在更底层调用我们上2节课的知识
--- Executor
-- statementHandler
--ParameterHandler ResultSetHandler
-- TypeHandler
}
int save(){
SqlSession.insert(namespace.id,参数)
}
}
二.自己大概实现一下动态代理
书写EmpMapper接口
进行测试
@Test
public void textAop() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSession sqlSession = sqlSessionFactoryBuilder.build(is).openSession();
MyMapperProxy myMapperProxy = new MyMapperProxy(sqlSession,EmpMapper.class);
//获得sqlSession啦 自己使用一些动态代理
/*
第一个参数:类加载器
第二个参数:原始类的接口
第三个参数:InvocationHandler的实现类
*/
EmpMapper empMapper =(EmpMapper) Proxy.newProxyInstance(Text.class.getClassLoader(),
new Class[]{EmpMapper.class},
myMapperProxy
);
List<Employee> list = empMapper.getAllEmployee();
System.out.println(list);
}
实现类如下
public class MyMapperProxy implements InvocationHandler {
private SqlSession sqlSession; //我们需要调用SqlSession.方法() 所以需要SqlSession的对象
private Class nameClass; // 用来获得namespace的
public MyMapperProxy(SqlSession sqlSession, Class nameClass) {
this.sqlSession = sqlSession;
this.nameClass = nameClass;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//因为我们只有一个查询方法方法,所以就是调用selectList
return sqlSession.selectList(nameClass.getName() + "." + method.getName());
}
}
进行测试,测试结果如下:
所以可以得知我们的分析是没有问题的。
三.简单通过源码去了解动态代理的实现
对于这个,我们根据我们上面的分析,mapperProxy 应该实现了InvocationHandler的接口
观察其invoke方法
观察execute方法
所以,我们通过这就明白了Mybatis的第一种形式与第二种形式的联系啦!