io包

io包即输入/输出包,负责完成 MyBatis中与输入/输出相关的操作。

说到输入/输出,首先想到的就是对磁盘文件的读写。在 MyBatis的工作中,与磁盘文件的交互主要是对 xml配置文件的读操作。因此,io包中提供对磁盘文件读操作的支持。

除了读取磁盘文件的功能外,io包还提供对内存中类文件(class文件)的操作。

背景知识

单例模式

单例模式(Singleton Pattern)是一种非常简单的设计模式。使用了单例模式的类提供一个方法得到该类的对象,并且总保证这个对象是唯一的。

例如,代码9-1就实现了一个单例模式的类。在该类中,构造方法被 private声明,因此无法通过外部获得 Singleton 对象。获取 Singleton 对象的唯一方式就是调用 getInstance方法,而每次访问 getInstance方法得到的对象都来自 INSTANCE属性。INSTANCE属性是一个静态属性,全局唯一。通过以上的机制保证了全局只有一个 Singleton对象。

【代码9-1】

从多线程安全、懒加载等角度考虑,单例模式还有很多种写法。我们这里不再展开,感兴趣的读者可以自己学习。

代理模式

代理模式(Proxy Pattern)是指建立某一个对象的代理对象,并且由代理对象控制对原对象的引用。

例如,我们不能直接访问对象 A,则可以建立对象 A的代理对象 AProxy。这样,就可以通过访问 A Proxy来间接地使用对象 A的功能。AProxy就像 A的对外联络人一般。图9-1给出了代理模式类图。

图9-1 代理模式类图

代理模式能够实现很多功能:· 隔离功能:通过建立一个目标对象的代理对象,可以防止外部对目标对象的直接访问,这样就使得目标对象与外部隔离。我们可以在代理对象中增加身份验证、权限验证等功能,从而实现对目标对象的安全防护。

· 扩展功能:对一个目标对象建立代理对象后,可以在代理对象中增加更多的扩展功能。例如,可以在代理对象中增加日志记录功能,这样对目标对象的访问都会被代理对象计入日志。

· 直接替换:对一个目标对象建立代理对象后,可以直接使用代理对象完全替换目标对象,由代理对象来实现全部的功能。例如,MyBatis 中数据库操作只是一个抽象方法,但实际运行中会建立代理对象来完成数据库的读写操作。

静态代理

静态代理就是代理模式最简单的实现。所谓“静态”,是指被代理对象和代理对象在程序中是确定的,不会在程序运行过程中发生变化。

例如,我们为用户类设置一个如代码9-2所示的接口类 UserInterface,然后在其中增加一个打招呼的抽象方法 sayHello。

【代码9-2】

实现 UserInterface接口的被代理类代码如代码9-3所示。

【代码9-3】

下面为被代理类增加一个代理类。代理类中调用了被代理类的 sayHello方法,并在此方法的基础上增加了新的功能:在打招呼前后增加开场语句和结束语句。代码9-4 展示了该代理类。

【代码9-4】

下面通过代码9-5调用代理对象中的方法。

【代码9-5】

程序运行结果如图9-2 所示。可以看到,通过代理对象执行了被代理对象的方法,并且被代理对象的方法前后新增加了一些功能。在整个过程中不需要被代理对象自身做出任何的更改。

图9-2 程序运行结果

示例项目类图如图9-3所示。

图9-3 示例项目类图

但是静态代理也有一些局限性,最明显的就是代理对象和被代理对象是在程序中写死的,显然不够灵活。动态代理则没有此弊端,我们会在 10.1.3节进行介绍。

VFS

磁盘文件系统分为很多种,如 FAT、VFAT、NFS、NTFS等。不同文件系统的读写操作各不相同。VFS(Virtual File System)作为一个虚拟的文件系统将各个磁盘文件系统的差异屏蔽了起来,提供了统一的操作接口。这使得上层的软件能够用单一的方式来跟底层不同的文件系统沟通,如图9-4所示。

图9-4 VFS的作用

在操作磁盘文件时,软件程序不需要和实体的文件系统打交道,只需要和 VFS沟通即可。这使得软件系统的磁盘操作变得更为简单。

VFS实现类

MyBatis的 io包中 VFS的作用是从应用服务器中找寻和读取资源文件,这些资源文件可能是配置文件、类文件等。io包中 VFS相关类主要有三个,图9-5展示了它们的类图。

图9-5 VFS类图

DefaultVFS类和 JBoss6VFS类是 VFS类的两个实现类。在确定了具体的实现类之后,外部只需通过 VFS中的方法即可完成外部文件的读取。

VFS类中的主要属性如代码9-6所示,两个属性中保存了内置和用户自定义的 VFS实现类。

【代码9-6】

VFS 类中含有一个内部类 VFSHolder,该类使用了单例模式。其中的 createVFS 方法能够对外给出唯一的 VFS实现类。VFSHolder类带注释的源码如代码9-7所示。

【代码9-7】

在 VFSHolder类的 createVFS方法中,先组建一个 VFS实现类的列表,然后依次对列表中的实现类进行校验。第一个通过校验的实现类即被选中。在组建列表时,用户自定义的实现类放在了列表的前部,这保证了用户自定义的实现类具有更高的优先级。

内部类 VFSHolder中最终确定的 VFS实现类会被放入 INSTANCE变量中。这样,当外部调用 VFS类的 getInstance方法时就可以拿到该 VFS实现类的对象,如代码9-8所示。

【代码9-8】

MyBatis中为 VFS提供了两个内部实现类,分别是 DefaultVFS类和

JBoss6VFS类,下面分别进行介绍。

DefaultVFS类

DefaultVFS 作为默认的 VFS 实现类,其 isValid 函数恒返回 true。因此,只要加载DefaultVFS类,它一定能通过 VFS类中 VFSHolder单例中的校验,并且在进行实现类的校验时 DefaultVFS排在整个校验列表的最后。因此,DefaultVFS成了所有 VFS实现类的保底方案,即最后一个验证,但只要验证一定能通过。

除了 isValid方法外,DefaultVFS中还有以下几个方法。

· list(URL,String):列出指定 url下符合条件的资源名称;

· listResources(JarInputStream,String):列出给定 jar包中符合条件的资源名称;

· findJarForResource(URL):找出指定路径上的 jar包,返回jar包的准确路径;· getPackagePath(String):将 jar包名称转为路径;

· isJar:判断指定路径上是否是 jar包。

以上方法均采用直接读取文件的方式来实现,结构并不复杂,我们不再展开介绍。

JBoss6VFS类

JBoss是一个基于 J2EE的开放源代码的应用服务器,JBoss6是 JBoss中的一个版本。JBoss6VFS即为借鉴 JBoss6设计的一套 VFS实现类。

在 JBoss6VFS中主要存在两个内部类。

· VirtualFile:仿照 JBoss中的 VirtualFile类设计的一个功能子集;

· VFS:仿照 JBoss中的 VFS类设计的一个功能子集。

阅读 VirtualFile和 VFS中的方法便可以发现,这些方法中都没有实现具体的操作,而是调用 JBoss中的相关方法。

以代码9-9展示的 VirtualFile中的 getPathNameRelativeTo方法为例,方法中直接使用invoke语句,将操作转给了 org.jboss.vfs.VirtualFile类中的 getPathNameRelativeTo方法。因此,这里使用了代理模式,此处的 VirtualFile内部类是 JBoss中 VirtualFile的静态代理类。

【代码9-9】

同理,VFS内部类是 JBoss中 VFS的静态代理类。

在 JBoss6VFS类中,两个内部类 VirtualFile和 VFS都是代理类,只负责完成将相关操作转给被代理类的工作。那么,要想使 JBoss6VFS类正常工作,必须确保被代理类存在。

确定被代理类是否存在的过程在 JBoss6VFS类的 initialize方法中完成。该方法由静态代码块触发,因此会在类的加载阶段执行,如代码9-10所示。

【代码9-10】

在初始化方法中,会尝试从 JBoss 的包中加载和校验所需要的类和方法。最后,还通过返回值对加载的方法进行了进一步的校验。而在以上的各个过程中,只要发现加载的类、方法不存在或者返回值发生了变化,则认为 JBoss 中的类不可用。在这种情况下,checkNotNull方法和 checkReturnType方法中会调用 setInvalid 方法将 JBoss6VFS的valid字段设置为 false,表示 JBoss6VFS类不可用。

类文件的加载

除了从磁盘中读取普通文件外,从磁盘中获取类文件(Class文件)并加载成一个类也是一种常用的功能。

要把类文件加载成类,需要类加载器的支持。ClassLoaderWrapper类中封装了五种类加载器,而 Resources 类又对 ClassLoaderWrapper类进行了一些封装。下面我们重点关注ClassLoaderWrapper类。

ClassLoaderWrapper的五种类加载器由 getClassLoaders方法给出,如代码9-11所示。

【代码9-11】

这五种类加载器依次是:

· 作为参数传入的类加载器,可能为 null;· 系统默认的类加载器,如未设置则为 null;

· 当前线程的线程上下文中的类加载器;

· 当前对象的类加载器;

· 系统类加载器,在 ClassLoaderWrapper的构造方法中设置。

以上五种类加载器的优先级由高到低。在读取类文件时,依次到上述五种类加载器中进行寻找,只要某一次寻找成功即返回结果。

classForName 方法是一个根据类名找出指定类的方法,下面以该方法为例,查看五种类加载器是如何轮番上阵发挥作用的。整个过程如代码9-12所示。

【代码9-12】

ResolverUtil类

ResolverUtil是一个工具类,主要功能是完成类的筛选。这些筛选条件可以是:

· 类是否是某个接口或类的子类;

· 类是否具有某个注解。为了能够基于这些条件进行筛选,ResolverUtil中设置有一个内部接口 Test。Test是一个筛选器,内部类中有一个抽象方法 matches来判断指定类是否满足筛选条件。图9-6给出了 Test接口及其实现类的类图。

图9-6 Test接口及其实现类的类图

如上所示,Test内部类有两个实现类,都重写了 matches方法。

· IsA类中的 matches方法可以判断目标类是否实现了某个接口或者继承了某各类;

· AnnotatedWith类中的 matches方法可以判断目标类是否具有某个注解。

最终通过校验的类会放到 ResolverUtil类的 matches属性中。

这样一来,在读取某个路径上的类文件时,还可以借助 ResolverUtil对类文件进行一些筛选。ResolverUtil中的 find方法即支持筛选出指定路径下的符合指定条件的类文件,代码9-13是该方法带注释的源码。

【代码9-13】

上述方法中传入的 Test参数可以是 IsA对象,也可以是 AnnotatedWith对象,这样就可以将 packageName 路径下所有符合条件的类文件找出来。真正触发测试的是addIfMatching子方法,该方法带注释的源码如代码9-14所示。

【代码9-14】

本文给大家讲解的内容是通用源码阅读指导mybatis源码详解: io包

  1. 下篇文章给大家讲解的是通用源码阅读指导mybatis源码详解: logging包;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

封装成jar包_通用源码阅读指导mybatis源码详解:io包相关推荐

  1. Caddy源码阅读(一)Run详解

    Caddy源码阅读(一)Run详解 前言 本次系列会讲解 caddy 整个生命周期涉及到的源码. 平时我们使用 caddy 都是使用 它的 二进制 分发文件,现在来分析 caddy 的 Run 函数. ...

  2. idea 导出war包_使用IDEA实现远程代码DEBUG调试教程详解

    我们在使用 IDEA DEBUG调试代码的时候,常常见到控制台会输出一句这样的话:「Connected to the target VM, address: '127.0.0.1:62981', tr ...

  3. miui怎么用第三方图标包_空气能热水器怎么用?控制面板的图标详解来了

    与普通热水器不同,空气能热水器有着独立的线控器显示屏,在使用过程中也有着不同于一般热水器的操作步骤,很多消费者使用过程中找不到说明书了,这么多图标不知道啥意思怎么办?一起来了解一下空气能热水器的线控器 ...

  4. Eclipse中如何把自己写的方法封装成jar包供其他项目使用

    Eclipse中如何把自己写的方法封装成jar包供其他项目使用 1.第一步.首先自己写一个方法: 2.右键项目名称(Demo)->选择Export-->选择JAR file,然后选择下一步 ...

  5. 源码通透-mybatis源码分析以及整合spring过程

    源码通透-mybatis源码分析以及整合spring过程 mybatis源码分析版本:mybaits3 (3.5.0-SNAPSHOT) mybatis源码下载地址:https://github.co ...

  6. 【流媒体开发】VLC Media Player - Android 平台源码编译 与 二次开发详解 (提供详细800M下载好的编译源码及eclipse可调试播放器源码下载)

    作者 : 韩曙亮  博客地址 : http://blog.csdn.net/shulianghan/article/details/42707293 转载请注明出处 : http://blog.csd ...

  7. Mybatis源码学习(三)SqlSession详解

    前言 上一章节我们学习了SqlSessionFactory的源码,SqlSessionFactory中的方法都是围绕着SqlSession来的.,那么SqlSession又是什么东东呢?这一章节我们就 ...

  8. 以太坊源码阅读5——POW源码分析

    以太坊源码阅读5--POW源码分析 介绍 POW,proof of work,即工作量证明,是著名公bitcoin所采用的共识算法.简单来说,pow就是一个证明,由矿工使用算力进行计算(挖矿),竞争记 ...

  9. centos7 mysql 源码安装_CentOS7.4 源码安装MySQL8.0的教程详解

    MySQL 8 正式版 8.0.11 已发布,官方表示 MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量的改进和更快的性能! 以下为本人2018.4.23日安装过程的记录.整个过程大 ...

最新文章

  1. 2019年全球数字化转型现状研究报告
  2. 每个人都应该懂点函数式编程
  3. insert数据时,获取插入数据的id
  4. Fragment 退出动画导致fragment退出失败问题(罕见问题)
  5. new 一个结构体数组_每天一个IDA小技巧(四):结构体识别
  6. WebService简单示例
  7. php有lambda表达式吗,Python中lambda表达式的简单介绍(附示例)
  8. linux保存python文件_告诉Python将.txt文件保存到Linux上的某个目录 - python
  9. python websocket django vue_Django资料 Vue实现网页前端实时反馈输出信息
  10. leetcode 506 相对名次
  11. AI 帮程序员找 Bug,一键快速预测
  12. activiti 作业执行器定时开始事件
  13. 医用耗材管理系统设计思路分享来自北京博奥智源
  14. xshell5产品秘钥
  15. 什么是瑞利分布和准静态平坦衰落信道?
  16. 科学家研发真实版的《星际迷航》牵引光束
  17. Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗
  18. PPT文件不能编辑如何解决?
  19. k8s 详解 pod 生命周期 容器探测(live and ready) 钩子函数 pod的重启策略
  20. presto日期转换及计算

热门文章

  1. SQLite多线程写锁文件解决方案
  2. 4-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案升级篇(远程升级WIFI内部程序)
  3. Spring MVC-页面重定向示例(转载实践)
  4. 72. Edit Distance
  5. [转]MIPS 下非对齐访问的问题
  6. WAV格式中常见的压缩编码
  7. Datalist嵌套以及属性生成器和页面样式
  8. elasticsearch的简介_以及实现原理---全文检索引擎ElasticSearch工作笔记001
  9. Mybatis Plus简介_代码_以及文档地址_以及前置知识---Mybatis Plus工作笔记001
  10. 基于Spring Security的认证方式_编程理解PasswordEncoder工作原理_Spring Security OAuth2.0认证授权---springcloud工作笔记125