Mybatis源码阅读之十一——反射

【系列目录】
Mybatis源码阅读之一——工厂模式与SqlSessionFactory

Mybatis源码阅读之二——模板方法模式与Executor

Mybatis源码阅读之三——JDBC解析与Mybatis封装

Mybatis源码阅读之四——装饰器模式与Mybatis中的各种Cache

Mybatis源码阅读之六——数据库连接池实现与hikariCP简析

Mybatis源码阅读之八——代理模式与Mybatis插件(pagehelper为例)

Mybatis源码阅读之九——适配器模式与日志模块

Mybatis源码阅读之九——适配器模式与日志模块

Mybatis源码阅读之十——Mybatis中优雅的责任链模式

【本文目录】


反射在Java中是一张背地里的手,随意挑动着类,肆意操纵着对象,随心所欲的访问人家private的方法或属性。

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control. —— oracle官方文档

Mybatis中反射相关目录:

类(Class)是Java的基础概念,万物皆对象,对象皆有类。
类的组成部分有:

  • 类的元信息(package,className,描述符)
  • 构造方法
  • 成员变量
  • 方法
  • 静态代码块

Reflector

在Mybatis中,类的概念被封装了起来,提供了更贴近我们(JavaBean)约定的的一个类——Reflector。

  • 看一下Reflector基本结构:
    能够发现他将一个类自身必须的描述信息基本包含在内:类,可读/可写属性,setter/getter方法及其类型,默认构造方法。
    下面从这些成员变量的获取入手,看一下具体的逻辑
  • 获取默认构造方法这里只取无参构造方法。
  • 获取getter:addGetMethods
    • 预处理,getter方法会按照boolean#isA的方法签名作为unique Key过滤,然后得到方法集合。
    • 第一步会将过滤所有getter且无参的方法,将其添加到Map<getter方法名,List<具体方法>>中。
    • 第二步,处理上述Map。
  • resolveGetterConflicts, getter方法存在两种冲突case,可见下第三四步
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBfjU1vc-1646617641336)(https://gitee.com/lele_fly/drawing-bed/raw/master/img/1645687259(1)].png)
    • 第一步,对一个具体的冲突getter进行处理,winner表示最终将选定的方法,isAmbiguous表示此getter无法识别。
    • 第二步,循环同一getter的多个方法,第一次指定第一个方法为winnner,然后直接跳出进行下一次循环。
    • 第三步,(tips boolean的getter应该以is开头,但是也有人可能使用get开头)若winner与当前类型相同并且不是boolean,说明父子类中有一个getA和一个isA同时返回值不是boolean,那么认为这种case无法处理。反之,如果返回值是boolean,那么找到isA作为getter方法。
    • 第四步,(tips:父类中方法的返回值可以是子类重写方法返回值的父类,比如父类方法返回Map,子类重写方法可以缩小范围返回HashMap)若winner与当前类型不同,则判断谁是谁的子类,并使用子类的getter。
    • 最后一步,将这些getter保存到getMethods成员变量,并且不明确的方法置为AmbiguousMethodInvoker,等你调用到就抛出异常
  • 获取Setter:addSetMethods,同addGetMethods差不多,区别在于一个是只招入参数量为1的,另一个冲突处理不同。
  • resolveSetterConflicts (setter的冲突主要因为重载)
    • 第一步,获取冲突的setters及其对应的getter,这里没有再用winner,换成了match(→_→)
    • 第二步,使用getter的返回值类型匹配,看是否能找到一个完美匹配的setter,找到则结束。
    • 第三步,如果setter未确定是模糊的,那么对比寻找一个更好的,这个对比逻辑与getter的比较类似。通过参数的父子找最子的那个,如果没有那么使用AmbiguousMethodInvoker。
    • 第四步,match增加到setter成员变量中去。
  • 获取成员变量:addFields
    这里没有太多逻辑,一点是final/static的变量不加载;另一点是会加载父类(祖宗)的成员变量。

ReflectorFactory

ReflectorFactory是Reflector的工厂类,同时提供了缓存实例的功能。

具体实现类如下,使用了一个Map来实现缓存实例的功能:

MetaClass

MetaClass是reflectorFactory和reflector的上层组合,与SqlSessionManager结构类似,提供了诸多反射所需的findProperty/getGetterNames/getGetterType/getGenericGetterType/getGetInvoker等方法。

使用场景
向上反查,会发现大部分是对paramType/resultType/resultMap等的封装,因为再Mybatis中不可能拿着业务系统定义的类操作,只能通过反射。

方法-Invoker

Mybatis中对方法的抽象——Invoker。

  • Invoker
    invoke方法用于执行,另外提供getType可以找到原class。
  • SetFieldInvoker/GetFieldInvoker: 对getter/setter的封装,直接使用filed进行操作。

  • MethodInvoker : 标准的方法执行器
  • AmbiguousMethodInvoker : 之前已经见过了,一个异常执行器

对象

Java中的对象相信大家都了解,那么JavaBean呢?
JavaBean其实就是符合getter/setter规范的对象:

  • 若干private实例字段;
  • 通过public方法来读写实例字段。

Mybatis对对象的基本封装是ObjectWrapper。

ObjectWrapper

ObjectWrapper接口定义了一个JavaBean基本应该具备的行为方法:

另外简单提一下,PropertyTokenizer是对字符串的封装,会对含有"."的字符串进行切割。

从UML图中可见,Wrapper拆分为三类:

  • BeanWrapper持有一个object对象以及一个反射得到class,实现了对象基本方法,对集合类方法抛出UnsupportedOperationException:
  • ColelctionWrapper:只实现了add和addAll,这个类的实现是为了让集合和普通对象统一上层接口
  • MapWrapper 实现了get/set等方法。

MetaObject

MetaObject是对对象信息,类信息的集合:

同时也管理了统一的行为,将objectWrapper和Reflector以及工厂类的特性集中在一起。

总结

本文我们学习了Mybatis对Class,Object的封装,其中对Reflector中getter/setter实现很值得参考,甚至我们可以直接拿来使用。

Mybatis的源码阅读系列就到此结束了,暂时没发现还有什么值得拿出来看一看的,以后如果有其他的亮点我们再来追加。


欢迎关注微信公众号 【JAVA技术分享官】,公众号首发,持续输出原创高质量JAVA开发者知识点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值