共计 3869 个字符,预计需要花费 10 分钟才能阅读完成。
一:先思考几个问题
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 其余属性
正文完