Mybatis实现原理

什么是Mybatis

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

Mybatis优势

  1. 与JDBC相比,减少了50%以上的代码量。
  2. MyBatis实现了接口绑定,无需自己写DAO实现类.
  3. MyBatis是最简单的持久化框架,小巧并且简单易学。
  4. MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用

Mybatis实现原理

我们知道,在Mybatis中声明一个interface接口,没有编写任何实现类,Mybatis就能返回接口实例,并调用接口方法返回数据库中的数据。实现这个功能的底层原理主要是底层采用了jdk动态代理。

动态代理

动态代理的主要功能是:通过拦截器方法回调,对目标target方法进行增强。言外之意就是为了增强目标target方法,这句话确实是讲的没有错误,但是在动态代理的过程中我们也可以做到连目标tagert都不要的霸权。

自定义自动映射器Mapper

首先我们先不研究源码,通过仿照源码的格式来自定义我们的自动映射器。
其中我们的domain类还是采用Student类,注意加上一个带参构造器。

public class Student {
    private Integer id;

    private String name;

    public Student(Integer id,String name) {
        this.id=id;
        this.name=name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "[" + "id:" + id + " name:" + name + "]";
    }
}

dao层接口中的方法:getStudentById()。

public interface StudentMapper {

    public Student getStudentById(Integer id);
}

实现InvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MapperProxy implements InvocationHandler {

    public <T> T newInstance(Class<T> clz) {
        return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                // 诸如hashCode()、toString()、equals()等方法,将target指向当前对象this
                return method.invoke(this, args);
            } catch (Throwable t) {
            }
        }
        
        return new Student((Integer) args[0], "hongchen.zhx");
    }
}

在MapperProxy类中,我们可以看到在执行Object对象的方法时,target被指向了this,此时target已经可以说是成为一个傀儡了。已经没有target什么事了。
编写测试代码进行测试。

public class Demo {
    public static void main(String[] args) {
        MapperProxy proxy = new MapperProxy();

        StudentMapper mapper = proxy.newInstance(StudentMapper.class);
        Student student= mapper.getStudentById(1001);

        System.out.println("ID:" + student.getId());
        System.out.println("Name:" + student.getName());

        System.out.println(mapper.toString());
    }
}

那么测试代码运行后的结果为:
在这里插入图片描述

真正的MapperProxy

通过以上自定义的Mapper映射器再来看相对应的源码就会轻松很多。

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
      //在执行诸如Object的方式时,target指向当前对象this。
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    //从缓存中获取MapperMethod对象,如果缓存中没有,则创建新的MapperMethod对象并添加到缓存中。
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //调用MapperMethod.execute()方法执行sql语句。
    return mapperMethod.execute(sqlSession, args);
  }

转自:https://yq.aliyun.com/articles/603907

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值