Mybatis的Mapper底层原理

总的来说是通过动态代理。动态代理的功能就是通过拦截器方法回调(invokeHandler),达到增强目标对象的目的。看下面代码,很关键一点就是InvocationHandler包含target对象。在invoke方法中会调用target的方法。

public class HelloWordProxy extends InvokeHandler{
  // 真正的本体
  private Object target;

  public Object bind(Object target) {
    this.target= target;
    return Proxy.newInstance(taget.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    
  }

  @Overrride
  public Object invoke(Object proxy, Method method, Object[] args) {
    System.out.println("before execute real target method");
    result = method.invoke(target, args);
    System.out.println("after execute real target method");
    return result;
  }
}

在Mybatis里面,会定义一个MapperProxy(实现InvocationHandler),先看MapperProxyFactory:

public class MapperProxyFactory<T> {

...
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T)Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInteface, methodCache);
    return newInstance(mapperProxy);
  }
}

重点关注上面的public方法,可以看出MapperProxy是用sqlSession创建的,并且Proxy.newInstance()方法的第三个参数就是这个MapperProxy对象本身(这个符合动态代理的基本创建方法)。

再看MapperProxy的执行代码:

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

public class MapperProxy implements InvocationHandler {

	@SuppressWarnings("unchecked")
	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) {
			}
		}
		MapperMethod mapperMethod = cachedMapperMethod(method);
		return mepperMethod.execute(sqlSession, args);
	}
}

method.invoke(this, args) 第一个参数往往是target, 而这里的target就是MapperProxy自己。所里这里起到的并不是增强target的功能,而是“取代”target的功能。而事实上,在Mybatis里面,从来就没出现target,target只是个占位符。

还要注意:最后mapperMethod.execute(sqlSesison, args)也很有意思,他是后序执行sql语句的入口,它会调用sqlSession的各种数据库操作方法,而这些方法就会去调用sqlSession的四大组件。这个会在后序的sql执行过程中详细介绍。



  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值