Mybatis 源码(六):Mapper接口代理对象创建
Mapper接口通过sqlSession的getMapper()方法获取,接口无法创建实例对象,获取到的是其代理对象,下面来看看Mapper接口的代理是如何创建的。
UserMapper mapper = sqlSession.getMapper(UserMapper.class)
Mapper接口对象创建,DefaultSqlSession#getMapper() 核心代码:
1 // 获取Mapper接口对象 2 public <T> T getMapper(Class<T> type) { 3 // 最终执行 MapperRegistry.getMapper 4 return configuration.<T>getMapper(type, this); 5 }
Configuration#getMapper() 核心代码:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
MapperRegister#getMapper() 核心代码:
1 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 2 // 查找指定type对应MapperProxyFactory对象 3 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); 4 // 如果mapperProxyFactory为空,则抛出异常 5 if (mapperProxyFactory == null) { 6 throw new BindingException("Type " + type + " is not known to the MapperRegistry."); 7 } 8 try { 9 // 创建实现了type接口的代理对象 10 return mapperProxyFactory.newInstance(sqlSession); 11 } catch (Exception e) { 12 throw new BindingException("Error getting mapper instance. Cause: " + e, e); 13 } 14 }
1、获取mapper接口代理工厂对象 - MapperProxyFactory
通过接口的Class对象,从全局配置对象configuration中mapperRegistry属性对象中获取指定Mapper接口对应的映射代理工厂MapperProxyFactory对象。实际是从mapperRegister的knownMappers属性中获取。
knownMappers在解析配置过程中完成了初始化,在Mybatis 源码(四):Mapper的解析工作中已做分析,此处不再赘述。
2、创建Mapper接口的代理对象
mapper接口代理工厂创建接口代理对象,MapperProxyFactory#newInstance() 核心代码:
1 // 创建接口代理对象 2 public T newInstance(SqlSession sqlSession) { 3 // 创建MapperProxy对象,每次调用都会创建新的mapperProxy对象 4 final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); 5 return newInstance(mapperProxy); 6 }
1、获取MapperProxy对象
MapperProxy用于创建Mapper接口的代理对象,类图如下:
MapperProxy继承自InvovationHandler接口,使用JDK动态代理创建代理对象需要使用Proxy的静态方法newProxyInstance,newProxyInstance方法详情:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
在获取Mapper接口的代理对象时,需使用MapperProxy对象作为参数完成代理对象的创建。
1 // 会话对象 - sqlSession 2 private final SqlSession sqlSession; 3 // mapper接口对应的Class对象 4 private final Class<T> mapperInterface; 5 // 用于缓存MapperMethod对象 6 // key是mapper接口中方法对应的Method对象,value是对应的MapperMethod对象,MapperMethod对象会完成SQL参数转换及SQL语句的执行功能 7 private final Map<Method, MapperMethod> methodCache; 8 9 // 构造函数 10 public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) { 11 this.sqlSession = sqlSession; 12 this.mapperInterface = mapperInterface; 13 this.methodCache = methodCache; 14 }
MapperProxy对象持有sqlSession对象、Mapper接口类型Class对象、方法缓存对象。
2、创建接口代理对象
重载方法newInstance() 创建接口代理对象,使用JDK动态代理完成Mapper接口代理对象的创建,MapperProxyFactory#newInstance() 核心代码:
1 // 使用jdk动态代理完成接口代理对象的创建 2 protected T newInstance(MapperProxy<T> mapperProxy) { 3 // 创建实现了mapperInterface接口的代理对象 4 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); 5 }
3、总结
根据接口类型 - Class对象,获取全局配置对象configuration中MapperRegister属性对象的knownMappers缓存属性中获取Mapper代理工厂对象创建MapperProxy对象,MapperProxy继承自InvovationHandler接口。
Mapper接口创建代理对象使用的是JDK动态代理,用MapperProxy作为参数完成代理对象的创建。