Vicene

Vicene 查看完整档案

北京编辑  |  填写毕业院校  |  填写所在公司/组织 segmentfault.com/u/vicene 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

Vicene 发布了文章 · 9月16日

mybatis源码分析二(看源码前的思考、源码入口)

一:先考虑几个问题

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主要对数据库增删改查进行了封装

image.png

上图基本上是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));
}

image.png

mybatis用建造者模式构造Configuration这个主要类,这个类主要包含数据源信息,别名缓存,mapper映射缓存等等,从super(new Configuration())开始构建Configuration,传递给其他子类构建Configuration其他属性
查看原文

赞 0 收藏 0 评论 0

Vicene 发布了文章 · 9月16日

mybatis源码分析一(ORM的思考)

一:ORM框架的思考

1:ORM框架

JDBC连接数据库:
加载JDBC驱动程序
创建数据库连接
创建Statement
执行SQL
遍历封装结果集
处理异常,关闭资源
JDBC连接数据存在哪些问题:
API繁琐,用户需频繁操作JDBC API
sql代码沾染业务代码,耦合深,且不复用
数据类型手动转换
……
ORM:
关系和对象之间的映射
ORM解决什么问题:
ORM帮用户解决像操作对象一样操作数据库层
通用api覆盖,sql代码业务代码分离
数据类型自动转换
……

2:如何简单设计ORM

先花时间思考如何设计ORM,哪些是抽象扩展点,哪些应是具体实现

image.png

那么mybatis做了件什么事情:对外提供接口,屏蔽底层复杂的细节

image.png

配置文件是xml还是properties文件或者?解析方式?
mapper映射源可以是注解?xml?或者json?解析方式?
mapper.xml如何映射接口?
接口参数如何映射sql?
sql执行器Bean设计?
mybatis用了哪些设计模式?为什么用这些设计模式?
......

二:如何看mybatis源码

1:mybatis官网

[https://mybatis.org/mybatis-3/zh/index.html](官网链接)

2:构件简单mybatis maven项目

导入mybatis、mysql jar
<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis</artifactId>
 <version>3.5.4</version>
</dependency>
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.42</version>
</dependency>
查看mybatis有哪些重要的模块,大概了解mybatis的功能,mybatis类命名较为规范,基本上看类名就知道类的作用

image.png

annotations 注解
binding 一些反射工具类
builder 构建重要对象的包
cache 缓存包
datasource 封装的数据源工厂和数据源
executor sql执行器
io io操作
javassist 一些java助手
logging 日志
mapping 映射
parsing 解析配置文件
session 会话
transaction 事务
查看原文

赞 0 收藏 0 评论 0

Vicene 关注了专栏 · 9月15日

JS漫步指南

一入JS深似海,希望这个专栏能在你乘风破浪的旅途中有所帮助。欢迎关注我的公众号:「JS漫步指南」,更多精彩等待发现!

关注 965

Vicene 关注了用户 · 9月15日

五绷带好评 @qzuser_57cb077436c88

关注 83

Vicene 关注了专栏 · 9月15日

终身学习者

我要先坚持分享20年,大家来一起见证吧。

关注 40945

Vicene 关注了专栏 · 9月15日

疯狂的技术宅

本专栏文章首发于公众号:前端先锋 。

关注 24568

Vicene 关注了用户 · 9月15日

思否编程 @sfbc

思否编程是由中国最大的新一代开发者社区 SegmentFault 孵化的在线编程培训平台,通过提升开发者 IT 职业技能,帮助开发者获得成功

思否编程网址:https://segmentfault.com/lives
申请成为讲师:https://jinshuju.net/f/HK5r9K

添加编程小姐姐微信:bobonadia

关注 4081

Vicene 关注了专栏 · 9月15日

一个程序员的成长

关注 443

Vicene 关注了专栏 · 9月15日

全栈修仙之路

聚焦全栈,专注分享 Angular、TypeScript、Node.js/Java 、Spring 技术栈等全栈干货。 欢迎小伙伴们关注公众号全栈修仙之路,一起升级打怪。

关注 5867

Vicene 关注了用户 · 9月15日

码哥字节 @magebyte

公众号「码哥字节」一个坚持原创分享技术开发者,主要分享 Java 分布式、微服务架构、源码拆解等

关注 1826

认证与成就

  • 获得 0 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 9月15日
个人主页被 41 人浏览