Mybatis源码分析

打印 上一主题 下一主题

主题 1839|帖子 1839|积分 5517

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Mybatis解析

0.引入

Mybatis源码也是对Jbdc的再一次封装,不管怎么进行包装,还是会有获取链接、preparedStatement、封装参数、执行这些步调的。本文来探索一下其运行原理。下面从最简单的mybatis利用案例,来看看mybatis的步调。
  1. public class Test01 {
  2.     // 测试方法!============
  3.     public static void main(String[] args) {
  4.         String configFile = "mybatis-config.xml";
  5.         try (
  6.             // 1. 加载配置文件
  7.             InputStream inputStream = Resources.getResourceAsStream(configFile)) {
  8.             // 2. 创建 SqlSessionFactory 对象
  9.             SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  10.             // 3. 获取 SqlSession 对象
  11.             SqlSession sqlSession = sessionFactory.openSession();
  12.             // 获取mapper
  13.             InventoryMapper inventoryMapper = sqlSession.getMapper(InventoryMapper.class);
  14.             // 调用mapper的方法
  15.             List<Inventory> allInventory = inventoryMapper.getAllInventory();
  16.             for (Inventory inventory : allInventory) {
  17.                 System.out.println(inventory);
  18.             }
  19.             
  20.             // System.out.println(inventoryMapper.getInventoryById(1));
  21.         } catch (IOException e) {
  22.             throw new RuntimeException(e);
  23.         }
  24.     }
  25. }
  26. // 实体类对象
  27. @AllArgsConstructor
  28. @NoArgsConstructor
  29. @Data
  30. public class Inventory implements Serializable {
  31.     private static final long serialVersionUID = 1L;
  32.     private Integer goodsId;
  33.     private String goodsName;
  34.     private Date createTime;
  35.     private Date modifyTime;
  36.     private Integer inventory;
  37. }
复制代码
数据库配置文件
  1. db.driver=com.mysql.cj.jdbc.Driver
  2. db.url=jdbc:mysql://127.0.0.1:3306/trans_inventory?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
  3. db.username=root
  4. db.password=123456
复制代码
配置文件如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
  3. <configuration>
  4.     <properties resource="db.properties" />
  5.     <settings>
  6.         
  7.         <setting name="mapUnderscoreToCamelCase" value="true"/>
  8.     </settings>
  9.    
  10.     <environments default="development">
  11.         <environment id="development">
  12.             
  13.             <transactionManager type="jdbc" />
  14.             
  15.             <dataSource type="pooled">
  16.                 <property name="driver" value="${db.driver}" />
  17.                 <property name="url" value="${db.url}" />
  18.                 <property name="username" value="${db.username}" />
  19.                 <property name="password" value="${db.password}" />
  20.             </dataSource>
  21.         </environment>
  22.     </environments>
  23.     <mappers>
  24.         <mapper resource="mapper/InventoryMapper.xml" />
  25.     </mappers>
  26. </configuration>
复制代码
mapper接口和xml文件
  1. public interface InventoryMapper {
  2.     List<Inventory> getAllInventory();
  3.     Inventory getInventoryById(@Param("id") Integer id);
  4. }
复制代码
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3.         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4.         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.feng.mapper.InventoryMapper">
  6.     <select id="getAllInventory" resultType="com.feng.entity.Inventory">
  7.         select *
  8.         from inventory
  9.     </select>
  10.    
  11.     <select id="getInventoryById" resultType="com.feng.entity.Inventory">
  12.         select *
  13.         from inventory
  14.         where goods_id = #{id}
  15.     </select>
  16. </mapper>
复制代码
1.加载配置文件

InputStream inputStream = Resources.getResourceAsStream(configFile)
可以看到是这一行代码。其中Resources是Mybatis的工具类。从这个开始一层一层往下看
  1. public class Resources {
  2.     // new 了一个ClassLoaderWrapper对象
  3.     private static final ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
  4.    
  5.         public static InputStream getResourceAsStream(String resource) throws IOException {
  6.         return getResourceAsStream(null, resource);
  7.     }   
  8.    
  9.     // loader = null, resource = "xxxx.xml"
  10.     public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
  11.         // ====================== 这一行
  12.         InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
  13.         if (in == null) {
  14.           throw new IOException("Could not find resource " + resource);
  15.         }
  16.         return in;
  17.     }
  18. }
  19. public class ClassLoaderWrapper {
  20.     ClassLoader defaultClassLoader;
  21.     ClassLoader systemClassLoader;
  22.         // --------- 构造函数
  23.     ClassLoaderWrapper() {
  24.         try {
  25.             // jdk的方法,得到系统类加载器
  26.             systemClassLoader = ClassLoader.getSystemClassLoader();
  27.         } catch (SecurityException ignored) {
  28.             // AccessControlException on Google App Engine
  29.         }
  30.     }
  31.    
  32.     public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
  33.         // getResourceAsStream()方法里面用到了 getClassLoaders(null)
  34.         return getResourceAsStream(resource, getClassLoaders(classLoader));
  35.     }
  36.     // 得到所有的类加载器:::classLoader = null
  37.     ClassLoader[] getClassLoaders(ClassLoader classLoader) {  
  38.         return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
  39.                                   getClass().getClassLoader(), systemClassLoader };
  40.     }
  41.     // 遍历所有的类加载器,谁加载到了就返回谁的inputStream
  42.     InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
  43.         for (ClassLoader cl : classLoader) {
  44.             if (null != cl) {
  45.                 // try to find the resource as passed
  46.                 InputStream returnValue = cl.getResourceAsStream(resource);
  47.                 // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
  48.                 if (null == returnValue) {
  49.                     returnValue = cl.getResourceAsStream("/" + resource);
  50.                 }
  51.                 if (null != returnValue) {
  52.                     return returnValue;
  53.                 }
  54.             }
  55.         }
  56.         return null;
  57.     }
  58. }
复制代码
主要是通过ClassLoader.getResourceAsStream()方法获取指定的classpath路径下的Resource
2.创建SqlSessionFactory
  1. // 2. 创建 SqlSessionFactory 对象
  2. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
复制代码
第一步,无参构造函数创建了一个SqlSessionFactoryBuilder对象,然后调用其build方法。这很明显是“建造者设计模式”。
主要来看后面的build(inputStream)方法
[code]public class SqlSessionFactoryBuilder {    public SqlSessionFactory build(InputStream inputStream) {        return build(inputStream, null, null);    }        public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {        try {          //1.创建一个xml解析的builder,是建造者模式          XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);          // 2.上面创建的parser.parse()【可以理解为创建Configuration对象,并设置其属性】          return build(parser.parse()); // 3.build出SqlSessionFactory        } catch (Exception e) {          throw ExceptionFactory.wrapException("Error building SqlSession.", e);        } finally {          ErrorContext.instance().reset();          try {            if (inputStream != null) {              inputStream.close();            }          } catch (IOException e) {            // Intentionally ignore. Prefer previous error.          }        }     }    // 3.我们发现SqlSessionFactory默认是DefaultSqlSessionFactory类型的    public SqlSessionFactory build(Configuration config) {        return new DefaultSqlSessionFactory(config);     }}// XMLConfigBuilder.java内里public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {    this(Configuration.class, inputStream, environment, props);  }public XMLConfigBuilder(Class
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

河曲智叟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表