首页 技术 正文
技术 2022年11月14日
0 收藏 479 点赞 2,928 浏览 5216 个字

1.通过调试,session调用的getMapper是其实现类DefaultSQLSession中的

        //1.读取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建 SqlSessionFactory 的构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用构建者创建工厂对象 SqlSessionFactory
SqlSessionFactory factory = builder.build(in);
//4.使用 SqlSessionFactory 生产 SqlSession 对象
SqlSession session = factory.openSession();
//5.使用 SqlSession 创建 dao 接口的代理对象
IBookDao bookDao = session.getMapper(IBookDao.class);
//6.使用代理对象执行查询所有方法
List<Book> books = bookDao.selectAll();
for (Book book : books) {
System.out.println(book);
}
//7.释放资源
session.close();
in.close();

2.在DefaultSQLSession类中getMapper方法如下,里面调用Configuration类的泛型方法<T> T getMapper(Class<T> type)

@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}

3.在Configuration类中查看getMapper(type, sqlSession)方法,里面调用的是MapperRegistry类里面的getMapper(type, sqlSession)方法。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}

4.进入MapperRegistry类里面查看getMapper(type, sqlSession)方法。里面通过属性knownMappers里面的方法get(Object key)获取MapperProxyFactory<T>泛型类,使用这个类里面的newInstance(SqlSession sqlSession)方法。

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();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);
}
}

5.进入MapperProxyFactory<T>泛型类,查看newInstance(SqlSession sqlSession)方法如下;这里面生成一个MapperProxy<T>对象mapperProxy,然后使用T newInstance(MapperProxy<T> mapperProxy)实现动态代理。其中MapperProxy<T>类实现了接口InvocationHandler。重写了Object invoke(Object proxy, Method method, Object[] args)方法

 protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
} public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}

6.查看MapperProxy<T>类里的invoke方法.

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try { if (Object.class.equals(method.getDeclaringClass())) {//并不是每个方法都需要调用代理对象进行执行,如果这个方法是Object中通用的方法,则无需执行
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {//判断是不是接口默认方法,1.8之后接口就有默认方法了
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//从缓存中获取MapperMethod对象,如果缓存中没有,则创建一个,并添加到缓存中
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 执行方法对应的 SQL 语句
return mapperMethod.execute(sqlSession, args);
}

7.查看MapperMethod 类的execute方法,这个方法是执行sql的主要方法,根据我写的程序这里是调用executeForMany方法,实际上这个方法DefaultSqlSession类里面的selectList方法。

 public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
//insert语句的处理逻辑
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
//update语句的处理逻辑
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
//delete语句的处理逻辑
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
//select语句的处理逻辑
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}

private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
} else {
result = sqlSession.<E>selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}

在这里,动态代理过程就完成了。大致执行过程是  sqlSession.getMapper()【这个sqlSession实际上是 DefaultSqlSession】—–调用—->Configuration.getMapper()—–调用—>MapperRegistry.getMapper() ——调用–>MapperProxyFactory.newInstance() ——-调用—-> Proxy.newProxyInstance()【其中的InvocationHandler接口由实现类MapperProxy代替】——invoke—–>MapperMethod.execute()—–调用—–>DefaultSqlSession.相应方法

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,948
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,474
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,287
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,102
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,734
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,769