MyBatis反射模块分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/newbie0107/article/details/102754109

我们一开始首先使用了我们最最基础的 JDBC连接MySQL数据库 ,并获取数据放到了我们的JavaBean之中,从那个过程中,我们就会发现我们自己获取数据的几个基本的步骤
在这里插入图片描述

我们在使用JDBC连接数据库时,我们获取到数据后,每次都需要自己手动实例化目标对象,并一一对应的进行手动赋值,这样太过于麻烦,那么我们的MyBatis是如何帮助我们解决的呢?



实例化目标对象

ObjectFactory: MyBatis每次创建结果对象的新实例时,它都会使用对象工厂( ObjectFactory)去构建POJO类


首先我们先看我们MyBatis是如何帮助我们实例化目标对象的,这里我们之前在 MyBatis配置 中也提到过
在这里插入图片描述
我们如何了解一些 Java 反射 的话,肯定就清楚我们要通过反射实例化一个对象的几种方法,这里我们就是通过获取到类的构造器来完成的。


这里我们先来看看 ObjectFactory 接口的默认实现类 DefaultObjectFactory
在这里插入图片描述
在这里插入图片描述

我们发现 ObjectFactory 提供了两种方法,一种是默认的无参构造方法,一种是有参构造方法,用法我们之前也介绍过,如一般默认无参构造方法,我们一般在 resultMap 中指定了一个实体类
在这里插入图片描述
我们还可以使用其无参的构造方法,如下
在这里插入图片描述
上述两种用法,我们在 基于XML的Mapper配置 —— resultType 和 resultMap 都有说明。



这里我们再看看其具体实例化过程,其实也就是判断下是无参还是有参,在调用其对应的构造方法,如下:
在这里插入图片描述

这里是不是特别的简单,我们可以用一个使用的Demo来理解它

public class Client {
    @Test
    public void test(){
        //创建ObjectFactory工厂类
        ObjectFactory objectFactory = new DefaultObjectFactory();
        //获取实例化的目标对象
        User user = objectFactory.create(User.class);
    }
}


对象属性的赋值


这里我们的目标对象是实例化出来了,那么我们无法把从数据库中的值赋值给POJO类呢?我们首先找到其对应的关系,如我们 resultMap下设置的对应关系
在这里插入图片描述

找到了其映射关系,我们就可以借助下面三个类,将我们对象的属性进行赋值

  • ReflectorFactory: 创建Reflector的工厂类, Reflector是mybatis反射模块的基础,每个Reflector对象都对应一个类,在其中缓存了反射操作所需要的类元信息
  • ObjectWrapper: 对对象的包装,抽象了对象的属性信息,他定义了一系列查询对象属性信息的方法,以及更新属性的方法
  • ObjectWrapperFactory: ObjectWrapper 的工厂类,用于创建ObjectWrapper

我们先看看看 ReflectorFactory 类,我们都知道我们Java中就有相关反射的一些API,这里我们MyBatis进行封装了一下,这里就是获取一些类的信息。它主要是创建 Reflector 类,而 Reflector 类中就封装了一些类相关的信息


Reflector

既然 ReflectorFactory 类是用于创建 Reflector 类的,那么我们先来看一看 Reflector 类,这里就是封装了对应POJO类的一些信息。包括一些方法名称,方法参数类型等等。
在这里插入图片描述

然后我们在实例化 Reflector 类时,根据传入的 Class 对象,我们会将上述的变量全部进行填充
在这里插入图片描述

这里我们在补充一点,我们之前在 基于XML的Mapper配置 —— resultType 和 resultMap 的最后,我们的提到过一点
在这里插入图片描述

那么它是如何生成 Getter/Setter 方法的呢?就是在我们这里代码中生成的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ReflectorFactory

现在我们应该对 Reflector 类有了一个基础的认识,那我们再来看看 ReflectorFactory 是如何生成 Reflector 类,其实非常简单,就是通过其默认的实现类 DefaultReflectorFactory 类
在这里插入图片描述

我们 DefaultReflectorFactory 还会将我们用过的类信息进行缓存。
在这里插入图片描述

我们在获取 Reflector 类时,如果开启了缓存会先从缓存中去拿,没有的话再去创建。
在这里插入图片描述

看完了Reflector类和ReflectorFactory类,我们也通过通过一个简单的代码理解下

public class Client {
    @Test
    public void test(){
        //创建ObjectFactory工厂类
        ObjectFactory objectFactory = new DefaultObjectFactory();
        //获取实例化的目标对象
        User user = objectFactory.create(User.class);

        //创建ReflectorFactory工厂类
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        //使用Reflector读取类元信息
		Reflector findForClass = reflectorFactory.findForClass(User.class);
		
		//通过过Reflector获取一些我们之前介绍Reflector中的信息
		Constructor<?> defaultConstructor = findForClass.getDefaultConstructor();
		String[] getablePropertyNames = findForClass.getGetablePropertyNames();
		String[] setablePropertyNames = findForClass.getSetablePropertyNames();
    }
}



ObjectWrapper

我们可以发现 ObjectWrapper 主要分为两类,一种是我们的普通的JavaBean,另一种主要就是我们用的集合类型
在这里插入图片描述

我们会发现我们的 ObjectWrapper 里面有一些方法我们比较的眼熟,就是和我们刚刚说过的 Reflector 类相关的方法
在这里插入图片描述

我们就来看看有关 JavaBean 的 BeanWrapper 类,其中有两个属性 Object 和 MetaClass ,我们 Object 就是我们的Java对象,而MetaClass里面其实就是我们上述所说的封装了类信息的 Reflector 类
在这里插入图片描述
在这里插入图片描述

所以我们那些 ObjectWrapper 中与 Reflector 类相关的方法,其实就是通过MetaClass调用了其Reflector类的方法。我们ObjectWrapper通过这些方法通过MetaClass拿到了我们类的信息,然后我们在通过ObjectWrapper给对象进行赋值,就是我们上述加了注释的几个方法。


这里可能不好理解,但是我们可以从使用这个类的代码中,来帮助我们理解

public class Client {
    @Test
    public void test(){
        //创建ObjectFactory工厂类
        ObjectFactory objectFactory = new DefaultObjectFactory();
        //获取实例化的目标对象
        User user = objectFactory.create(User.class);

        ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);


		//使用ObjectWrapper读取对象信息,并对对象属性进行赋值操作
		ObjectWrapper wrapperForUser = new BeanWrapper(metaObject, user);
		
		PropertyTokenizer prop = new PropertyTokenizer("userName");
		wrapperForUser.set(prop, "张三");
    }
}



MetaObject

刚刚在上面的例子,我们使用到了 MetaObject ,MetaObject有什么作用呢?它主要封装了对象元信息,包装了mybatis中五个核心的反射类。也是提供给外部使用的反射工具类,可以利用它可以读取或者修改对象的属性信息
在这里插入图片描述

这里我们看看如何使用 MetaObject 来进行映射关系,首先我们先模拟下我们从数据库中取出的数据,如我们之前使用JDBC取出数据时,是类似于一个Map的数据接口,所以这里我们就使用Map集合模拟取出的数据
在这里插入图片描述
在这里插入图片描述

然后我们都知道XML文件中的resultMap里面会有我们的映射关系,也是Map结构的
在这里插入图片描述
在这里插入图片描述

最后我们就来看看如何给我们的对象进行赋值

public class Client {
    @Test
    public void test(){
        //创建ObjectFactory工厂类
        ObjectFactory objectFactory = new DefaultObjectFactory();
        //获取实例化的目标对象
        User user = objectFactory.create(User.class);
        //创建ObjectWrapperFactory工厂类
        ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
        //创建ReflectorFactory工厂类
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);

        //使用反射工具类将行数据转换成POJO类
        BeanWrapper objectWrapper = (BeanWrapper) metaObject.getObjectWrapper();


        //模拟数据库行数据转化成对象
        //1.模拟从数据库读取数据
        Map<String, Object> dbResult = new HashMap<>();
        dbResult.put("id", 1);
        dbResult.put("real_name", "张三");
        //2.模拟映射关系
        Map<String, String> mapper = new HashMap<String, String>();
        mapper.put("id", "id");
        mapper.put("realName", "real_name");

        Set<Map.Entry<String, String>> entrySet = mapper.entrySet();
        for (Map.Entry<String, String> colInfo : entrySet) {
            String propName = colInfo.getKey();
            Object propValue = dbResult.get(colInfo.getValue());
            PropertyTokenizer proTokenizer = new PropertyTokenizer(propName);
            objectWrapper.set(proTokenizer, propValue);
        }
    }
}

这里和我们上一个例子几乎就是一样的,这里只是模拟了我们数据库取出数据,和XML文件中设置的映射关系,根据这两个来自动给我们的目标对象进行赋值。

猜你喜欢

转载自blog.csdn.net/newbie0107/article/details/102754109
今日推荐