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对象作为参数完成代理对象的创建。

  映射器代理 - 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作为参数完成代理对象的创建。

 

posted @ 2023-03-20 21:51  无虑的小猪  阅读(436)  评论(0编辑  收藏  举报