mybatis只有mapper接口是如何执行sql的呢?
mybatis已经成了系统开发必备的orm框架,开发者只需要提供mapper接口,就可以执行sql,返回预期结果。接口是不能直接运行的,那么mybatis是如何通过接口调用执行sql的?道理似乎很简单,只有接口没有实现,那肯定是通过动态代理生成的实现类。那mybatis又是如何通过动态代理来执行sql的呢?很多童鞋到这一步可能就哑火了,本文将告诉你答案。先来看下mybatis的基本流程,引用自官网
mybatis已经成了系统开发必备的orm框架,开发者只需要提供mapper接口,就可以执行sql,返回预期结果。接口是不能直接运行的,那么mybatis是如何通过接口调用执行sql的?
道理似乎很简单,只有接口没有实现,那肯定是通过动态代理生成的实现类。那mybatis又是如何通过动态代理来执行sql的呢?很多童鞋到这一步可能就哑火了,本文将告诉你答案。
先来看下mybatis的基本流程,引用自官网。通过读取全局配置文件构建sqlSessionFactory,然后拿到sqlSession,有了sqlSession就可以执行sql。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession()
配置文件mybatis-config.xml里承载了许多重要的信息,诸如typeAliases,environments等(暂不讨论),本文主要分析mapper动态代理,mapper接口不仅需要实现,还需要和mapper.xml文件关联起来。
跟踪一下解析mybatis-config.xml的过程,会发现配置文件最终会被解析并生成Configuration对象,所有的配置信息都在这里了。mappers节点内容会被添加到MapperRegistry,
protected final MapperRegistry mapperRegistry;
public <T> void addMapper(Class<T> type) {
this.mapperRegistry.addMapper(type);
}
再来看下MapperRegistry的相关方法,在addMapper中会将目标接口类型构建MapperProxyFactory,看名称就知道是一个mapper代理类工厂,离代理对象已经一步之遥了。
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
public <T> void addMapper(Class<T> type) {
this.knownMappers.put(type, new MapperProxyFactory(type));
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
return mapperProxyFactory.newInstance(sqlSession);
}
通过getMapper方法可以看到会返回代理类的实现MapperProxyFactory,我们知道jdk动态代理是通过Proxy和InvocationHandler实现的,可以猜测代理实现就是在MapperProxyFactory里通过Proxy完成的。
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
看到了熟悉的Proxy.newProxyInstance(jdk动态代理),还差一个InvocationHandler,可以看到对应的位置是MapperProxy。
public class MapperProxy<T> implements InvocationHandler, Serializable{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
这样动态代理实现类就完成了,mapper接口方法调用时,会触发代理类的invoke方法。剩余的工作就是根据类型.方法名找到对应的MappedStatement,最后查询数据库。
本文简要的分析了mybatis代理实现过程,还有许多细节地方没有带出,感兴趣的童鞋可以自行查看mybatis源码,跟踪一下,大有裨益。
觉得有用,点个关注。欢迎关注同名公众号【码农小麦】,感谢老铁。
更多推荐
所有评论(0)