一、目录
1、前言
2、配置文件加载
3、配置文件解析
4、SQL执行
5、结果集映射
6、Mybatis中的设计模式
7、总结
二、前言
1、mybatis框架图
如上为mybatis的框架图,在这篇文章中通过源码来重点看下数据处理层中的参数映射,SQL解析,SQL执行,结果映射
2、配置使用
获取mapper并操作数据库代码如下:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
LiveCourseMapper mapper = sqlSession.getMapper(LiveCourseMapper.class);
List<LiveCourse> liveCourseList = mapper.getLiveCourseList();
三、配置文件加载
配置文件加载最终还是通过
ClassLoader.getResourceAsStream来加载文件,关键代码如下:
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);
// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
四、配置文件解析
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 我们以 SqlSessionFactoryBuilder为入口,看下mybatis是如何解析配置文件,并创建SqlSessionFactory的。
SqlSessionFactoryBuilder.build方法实现如下:
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//解析出configuration对象,并创建SqlSessionFactory
return build(parser.parse());
重点为解析configuration对象,然后根据configuration创建DefualtSqlSessionFactory。
1、解析configuration
private void parseConfiguration(XNode root) {
try {
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectionFactoryElement(root.evalNode("reflectionFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
通过XPathParser解析configuration节点下的properties,settings,typeAliases,plugins,objectFactory,objectWrapperFactory,reflectionFactory,environments,databaseIdProvider,typeHandlers,mappers这些节点。解析过程大体相同,都是通过XPathParser解析相关属性、子节点,然后创建相关对象,并保存到configuration对象中。这块代码相对简单,大家阅读起来没什么难度。
(1)解析properties 解析properties,并设置到configuration对象下的variables属性,protected Properties variables = new Properties();
(2)解析settings 解析settings配置,如lazyLoadingEnabled(默认false),defaultExecutorType(默认SIMPLE),jdbcTypeForNull(默认OTHER),callSettersOnNulls(默认false)
(3)解析typeAliases 通过typeAliasRegistry来注册别名,别名通过key,value的方式来进行存储,mybatis默认会创建一些基础类型的别名,如string->String.class,int->Integer.class,map->Map.class,hashmap->HashMap.class,list->List.class。别名和class关系通过HashMap来存储,
private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();
(4)解析plugins 解析插件,然后设置Configuration的InterceptorChain。 Configuration: protected final InterceptorChain interceptorChain = new InterceptorChain();
InterceptorChain:
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
在创建的时候构造了拦截器链,在执行的时候也会经过拦截器链,此处为典型的责任链模式
(5)解析objectFactory 可以自定义ObjectFactory,对象工厂,默认为DefaultObjectFactory
(6)解析objectWrapperFactory 默认为
DefaultObjectWrapperFactory
(7)reflectionFactory 反射工厂,在通过反射创建对象时(如结果集对象),可以通过自定义的反射工厂来创建对象。objectFactory,objectWrapperFactory,reflectionFactory这又是典型的工厂模式,将对象的创建交由相应的工厂来创建。
(8)databaseIdProvider 用来支持不同的数据库,很少在项目中用到
(9)解析typeHandlers 解析TypeHandler并通过typeHandlerRegistry注册到configuration中,通过TYPE_HANDLER_MAP保存typeHandler:
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();复制代码
(10)解析mappers 读取通过url指定的配置文件,然后通过XmlMapperBuilder进行解析
2、解析mapper
解析mapper的入口为XmlMapperBuilder.parse方法,在解析的时候会解析cache-ref,cache&