《Mybatis 手撸专栏》第8章:把反射用到出神入化

🚀 优质资源分享 🚀

学习路线指引(点击解锁) 知识定位 人群定位
🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

作者:小傅哥
博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!😄

一、前言

为什么,读不懂框架源码?

我们都知道作为一个程序员,如果想学习到更深层次的技术,就需要阅读大量的框架源码,学习这些框架源码中的开发套路和设计思想,从而提升自己的编程能力。

事大家都清楚,但在实操上,很多码农根本没法阅读框架源码。首先一个非常大的问题是,面对如此庞大的框架源码,不知道从哪下手。与平常的业务需求开发相比,框架源码中运用了大量的设计原则和设计模式对系统功能进行解耦和实现,也使用了不少如反射、代理、字节码等相关技术。

当你还以为是平常的业务需求中的实例化对象调用方法,去找寻源码中的流程时,可能根本就找不到它是何时发起调用的、怎么进行传参、在哪处理赋值的等一连串的问题,都把一个好码农劝退在开始学习的路上。

二、目标

不知道大家在学习《手写 Mybatis》的过程中,是否有对照 Mybatis 源码一起学习,如果你有对照源码,那么大概率会发现我们在实现数据源池化时,对于属性信息的获取,采用的是硬编码的方式。如图 8-1 所示

图 8-1 数据源池化配置获取

  • 也就是 props.getProperty("driver")props.getProperty("url") 等属性,都是通过手动编码的方式获取的。
  • 那其实像 driver、url、username、password 不都是标准的固定字段吗,这样获取有什么不对的。如果按照我们现在的理解来说,并没有什么不对,但其实除了这些字段以外,可能还有时候会配置一些扩展字段,那么怎么获取呢,总不能每次都是硬编码。
  • 所以如果你有阅读 Mybatis 的源码,会发现这里使用了 Mybatis 自己实现的元对象反射工具类,可以完成一个对象的属性的反射填充。这块的工具类叫做 MetaObject 并提供相应的;元对象、对象包装器、对象工厂、对象包装工厂以及 Reflector 反射器的使用。那么本章节我们就来实现一下反射工具包的内容,因为随着我们后续的开发,也会有很多地方都需要使用反射器优雅的处理我们的属性信息。这也能为你添加一些关于反射的强大的使用!

三、设计

如果说我们需要对一个对象的所提供的属性进行统一的设置和获取值的操作,那么就需要把当前这个被处理的对象进行解耦,提取出它所有的属性和方法,并按照不同的类型进行反射处理,从而包装成一个工具包。如图 8-2 所示

图 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
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
可以使用以下代码创建对象的工具类: ```java import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class ReflectionUtil { /** * 通过类名创建对象 * @param className 类名 * @return 创建的对象 */ public static Object createObject(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class<?> clazz = Class.forName(className); return clazz.newInstance(); } /** * 通过类名和构造函数参数创建对象 * @param className 类名 * @param args 构造函数参数 * @return 创建的对象 */ public static Object createObject(String className, Object... args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<?> clazz = Class.forName(className); Class<?>[] parameterTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { parameterTypes[i] = args[i].getClass(); } Constructor<?> constructor = clazz.getConstructor(parameterTypes); return constructor.newInstance(args); } } ``` 其中,`createObject(String className)` 方法通过类名创建对象,`createObject(String className, Object... args)` 方法通过类名和构造函数参数创建对象。使用时,只需要传入类名和参数即可。注意,如果类的构造函数是私有的,需要使用 `getDeclaredConstructor()` 方法获取构造函数,并设置 `setAccessible(true)` 来允许访问私有构造函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

[虚幻私塾】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值