Mybatis动态代理源码分析(Mapper接口生成代理类)

Mybatis我相信大家都接触过,就不进行介绍了。 它目前是企业中最受欢迎的持久层框架,在用的过程中我们也产生很多疑问?最大的疑问莫过于mapper接口的动态代理了,这就需要我们从源码的角度去分析。

我们想使用Mybatis对数据库进行操作,必须要拿到SqlSession对象。

SqlSession sqlSession = sqlSessionFactory.openSession();

SqlSession接口提供了大量对数据库进行操作的抽象方法,其中这个方法,根据传入的mapper接口的Class对象,返回其代理对象。

<T> T getMapper(Class<T> var1);

SqlSession使用的默认实现是DefaultSqlSession。DefaultSqlSession中持有Configuration的引用,会调用Configuration提供的getMapper方法。

DefaultSqlSession类中

public Configuration getConfiguration() {
        return this.configuration;
}

public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
}

我们进入Configuration中,发现会调用MapperRegistry中的getMapper方法。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
}

MapperRegistry的getMapper方法会使用MapperProxyFactory最终生成代理类。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if(mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

分析

        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);

在配置阶段Configuration中会调用addMapper添加mapper接口的Class对象,最终调用MapperRegistry中的addMapper方法。放入Map中,key:Class<?>,value:MapperProxyFactory<?>。

    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

根据Class对象,取到MapperProxyFactory实例,调用newInstance(SqlSession sqlSession)方法。

public class MapperProxyFactory<T> {
	//mapper接口的Class对象
    private final Class<T> mapperInterface;
    
	//key:mapper接口中的抽象方法	value:代理对象所要调用的对象
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return this.mapperInterface;
    }

    public Map<Method, MapperMethod> getMethodCache() {
        return this.methodCache;
    }

	//使用jdk动态代理
    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

主要分析的方法

public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
}

MapperProxy实现了java.lang.reflect包下的InvocationHandler接口,我的理解是此接口是一个介于代理对象与被代理对象的统一管理者。

public class MapperProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
        	//判断方法是否继承自Object,如toString、equals等方法
            if(Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
			
			//针对jdk1.8的默认实现方法
            if(this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
		//获取MapperMethod 
        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        //执行相关的SQL语句操作
        return mapperMethod.execute(this.sqlSession, args);
    }
    
	//若key对应的value为空,会将第二个参数的返回值存入并返回
    private MapperMethod cachedMapperMethod(Method method) {
        return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
        	//创建MapperMethod对象
            return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
        });
    }
    
	其它方法忽略.....
}

最终调用其生成代理对象。

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

通过jdk提供的ProxyGenerator可以生成代理类的字节码文件。反编译如下:

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 

import java.lang.reflect.*;
import java.util.List;
import mybaits.mappers.userDao;

public final class UserDaoProxy extends Proxy
	implements userDao
{

	private static Method m1;
	private static Method m2;
	private static Method m3;
	private static Method m0;

	public UserDaoProxy(InvocationHandler invocationhandler)
	{
		super(invocationhandler);
	}

	public final boolean equals(Object obj)
	{
		try
		{
			return ((Boolean)super.h.invoke(this, m1, new Object[] {
				obj
			})).booleanValue();
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final String toString()
	{
		try
		{
			return (String)super.h.invoke(this, m2, null);
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final List select()
	{
		try
		{
			return (List)super.h.invoke(this, m3, null);
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	public final int hashCode()
	{
		try
		{
			return ((Integer)super.h.invoke(this, m0, null)).intValue();
		}
		catch (Error ) { }
		catch (Throwable throwable)
		{
			throw new UndeclaredThrowableException(throwable);
		}
	}

	static 
	{
		try
		{
			m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
				Class.forName("java.lang.Object")
			});
			m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
			m3 = Class.forName("mybaits.mappers.userDao").getMethod("select", new Class[0]);
			m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
		}
		catch (NoSuchMethodException nosuchmethodexception)
		{
			throw new NoSuchMethodError(nosuchmethodexception.getMessage());
		}
		catch (ClassNotFoundException classnotfoundexception)
		{
			throw new NoClassDefFoundError(classnotfoundexception.getMessage());
		}
	}
}

java反编译工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值