🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
作者:小傅哥
博客:https://bugstack.cn
沉淀、分享、成长,让自己和他人都能有所收获!😄
一、前言
为什么,读不懂框架源码?
我们都知道作为一个程序员,如果想学习到更深层次的技术,就需要阅读大量的框架源码,学习这些框架源码中的开发套路和设计思想,从而提升自己的编程能力。
事大家都清楚,但在实操上,很多码农根本没法阅读框架源码。首先一个非常大的问题是,面对如此庞大的框架源码,不知道从哪下手。与平常的业务需求开发相比,框架源码中运用了大量的设计原则和设计模式对系统功能进行解耦和实现,也使用了不少如反射、代理、字节码等相关技术。
当你还以为是平常的业务需求中的实例化对象调用方法,去找寻源码中的流程时,可能根本就找不到它是何时发起调用的、怎么进行传参、在哪处理赋值的等一连串的问题,都把一个好码农劝退在开始学习的路上。
二、目标
不知道大家在学习《手写 Mybatis》的过程中,是否有对照 Mybatis 源码一起学习,如果你有对照源码,那么大概率会发现我们在实现数据源池化时,对于属性信息的获取,采用的是硬编码的方式。如图 8-1 所示
- 也就是
props.getProperty("driver")
、props.getProperty("url")
等属性,都是通过手动编码的方式获取的。 - 那其实像 driver、url、username、password 不都是标准的固定字段吗,这样获取有什么不对的。如果按照我们现在的理解来说,并没有什么不对,但其实除了这些字段以外,可能还有时候会配置一些扩展字段,那么怎么获取呢,总不能每次都是硬编码。
- 所以如果你有阅读 Mybatis 的源码,会发现这里使用了 Mybatis 自己实现的元对象反射工具类,可以完成一个对象的属性的反射填充。这块的工具类叫做 MetaObject 并提供相应的;元对象、对象包装器、对象工厂、对象包装工厂以及 Reflector 反射器的使用。那么本章节我们就来实现一下反射工具包的内容,因为随着我们后续的开发,也会有很多地方都需要使用反射器优雅的处理我们的属性信息。这也能为你添加一些关于反射的强大的使用!
三、设计
如果说我们需要对一个对象的所提供的属性进行统一的设置和获取值的操作,那么就需要把当前这个被处理的对象进行解耦,提取出它所有的属性和方法,并按照不同的类型进行反射处理,从而包装成一个工具包。如图 8-2 所示
- 其实整个设计过程都以围绕如何拆解对象并提供反射操作为主,那么对于一个对象来说,它所包括的有对象的构造函数、对象的属性、对象的方法。而对象的方法因为都是获取和设置值的操作,所以基本都是get、set处理,所以需要把这些方法在对象拆解的过程中需要摘取出来进行保存。
- 当真正的开始操作时,则会依赖于已经实例化的对象,对其进行属性处理。而这些处理过程实际都是在使用 JDK 所提供的反射进行操作的,而反射过程中的方法名称、入参类型都已经被我们拆解和处理了,最终使用的时候直接调用即可。
四、实现
1. 工程结构
mybatis-step-07
└── src
├── main
│ └── java
│ └── cn.bugstack.mybatis
│ ├── binding
│ ├── builder
│ ├── datasource
│ │ ├── druid
│ │ │ └── DruidDataSourceFactory.java
│ │ ├── pooled
│ │ │ ├── PooledConnection.java
│ │ │ ├── PooledDataSource.java
│ │ │ ├── PooledDataSourceFactory.java
│ │ │ └── PoolState.java
│ │ ├── unpooled
│ │ │ ├── UnpooledDataSource.java
│ │ │ └── UnpooledDataSourceFactory.java
│ │ └── DataSourceFactory.java
│ ├── executor
│ ├── io
│ ├── mapping
│ ├── reflection
│ │ ├── factory
│ │ │ ├── DefaultObjectFactory.java
│ │ │ └── ObjectFactory.java
│ │ ├── invoker
│ │ │ ├── GetFieldInvoker.java
│ │ │ ├── Invoker.java
│ │ │ ├── MethodInvoker.java
│ │ │ └── SetFieldInvoker.java
│ │ ├── property
│ │ │ ├── PropertyNamer.java
│ │ │ └── PropertyTokenizer.java
│ │ ├── wrapper
│ │ │ ├── BaseWrapper.java
│ │ │ ├── BeanWrapper.java
│ │ │ ├── CollectionWrapper.java
│ │ │ ├── DefaultObjectWrapperFactory.java
│ │ │ ├── MapWrapper.java
│ │ │ ├── ObjectWrapper.java
│ │ │ └── ObjectWrapperFactory.java
│ │ ├── MetaClass.java
│ │ ├── MetaObject.java
│ │ ├── Reflector.java
│ │ └── SystemMetaObject.java
│ ├── session
│ ├── transaction
│ └── type
└── test
├── java
│ └── cn.bugstack.mybatis.test.dao
│ ├── dao
│ │ └── IUserDao.java
│ ├── po
│ │ └── User.java
│ ├── ApiTest.java