一:先考虑几个问题
1:BlogMapper是个接口,接口不能实例化,如何直接调用selectBlog并返回
public interface BlogMapper {
public Blog selectBlog(Long id);
}
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1L);
mybatis通过jdk提供动态代理解决以上问题,例如:
BlogMapper b = (BlogMapper) Proxy.
newProxyInstance(JdkProxy.class.getClassLoader(), new Class[]{BlogMapper.class}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在调用selectBlog方法的时候执行invoke
if (method.getName().equals("selectBlog"))
System.out.println(method.getName());
return null; }
});
b.selectBlog(1l);
2:XML解析
解析xml的方式有多种,DOM,SAX,DOM4J,JDOM各有优劣。mybatis通过SAX解析xml,并构造需要的对象及功能,XML映射接口功能
二:源码入口
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1L);
1:加载xml,ClassLoaderWrapper装饰模式增强ClassLoader功能
//mybatis封装Resources加载xml,实际上是调用classLoaderWrapper.getResourceAsStream
Resources.getResourceAsStream(resource);
//ClassLoaderWrapper##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;
}
//ClassLoaderWrapper##getResourceAsStream
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
return getResourceAsStream(resource, getClassLoaders(classLoader));
}
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
//加载资源
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue) {
//再次加载资源
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
//ClassLoaderWrapper获取多级类加载器加载xml
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
//参数指定的类加载器
classLoader,
//系统指定的默认加载器
defaultClassLoader,
//当前线程的类加载器
Thread.currentThread().getContextClassLoader(),
//当前类使用的类加载器
getClass().getClassLoader(),
//JVM启动时就加载了类加载器
systemClassLoader};
}
2:SqlSessionFactoryBuilder
SqlSessionFactoryBuilder主要构建SqlSessionFactory,SqlSessionFactory构建SqlSession,SqlSession主要对数据库增删改查进行了封装

上图基本上是mybatis的壳,为对外的接口类关系
看看build()方法中的细节
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//mybatis-config.xml 创建XMLConfigBuilderxml解析类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//返回DefaultSqlSessionFactory##Configuration
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//XMLConfigBuilder为主要解析xml类,其中主要调用封装的XPathParser解析
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//new Configuration()调用父类构造方法初始化一些值
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
//createDocument根据xml构建文档对象
this.document = createDocument(new InputSource(inputStream));
}

mybatis用建造者模式构造Configuration这个主要类,这个类主要包含数据源信息,别名缓存,mapper映射缓存等等,从super(new Configuration())开始构建Configuration,传递给其他子类构建Configuration其他属性
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。