MyBatis入门系列(14) -MyBatis运行原理之获取Mapper代理对象源码分析

怼烎@ 2023-10-10 13:02 25阅读 0赞

获取Mapper代理对象

在获取了SqlSession对象后,调用getMapper方法传入一个Mapper接口,就会返回一个实例对象,众所周知,接口是不能实例化的,那么返回的肯定是接口的代理对象。

  1. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

大致流程

在这里插入图片描述

源码分析

1. DefaultSqlSession.getMapper(type, this)

SqlSession对象为DefaultSqlSession,那么实际调用的是DefaultSqlSession.getMapper(type, this)方法,这个方式实际调用的又是configuration对象的getMapper方法。

  1. @Override
  2. public <T> T getMapper(Class<T> type) {
  3. // 调用configuration
  4. return configuration.<T>getMapper(type, this);
  5. }
2. Configuration.getMapper(Class type, SqlSession sqlSession)

configuration.getMapper()方法实际调用的是configuration对象中mapperRegistry的getMapper方法。

  1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  2. return mapperRegistry.getMapper(type, sqlSession);
  3. }
3. MapperRegistry.getMapper(Class type, SqlSession sqlSession)

mapperRegistry是Configuration的一个成员变量,其类为MapperRegistry,可以理解为Mapper注册器。

mapper注册器用于将所有的mapper接口添加到内存中,Mapper注册器自身维护着两个属性,config和knownMappers,其中knownMappers是一个Map集合。

  1. private final Configuration config;
  2. private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

SqlSessionFactory创建之后,mapperRegistry会完成初始化,knownMapper中存放各种键值对,键为每个每个mapper接口,值为MapperProxyFactory对象,MapperProxyFactory是一个工厂类,用于创建MapperProxy。

  1. knownMappers.put(type, new MapperProxyFactory<T>(type));

在这里插入图片描述
MapperRegistry获取Mapper对象的源码如下:

  1. /**
  2. * 获取Mapper 实例对象
  3. *
  4. * @param type 接口
  5. * @param sqlSession SqlSession
  6. * @return MapperProxy
  7. */
  8. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  9. // 在knownMappers中获取Mapper代理对象工厂
  10. final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  11. if (mapperProxyFactory == null) {
  12. throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  13. }
  14. try {
  15. return mapperProxyFactory.newInstance(sqlSession);
  16. } catch (Exception e) {
  17. throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  18. }
  19. }
4. mapperProxyFactory.newInstance(sqlSession)

mapper代理对象工厂通过newInstance()方法创建实例mapper接口对应的代理对象MapperProxy。

  1. /**
  2. *
  3. * @param sqlSession SqlSession
  4. * @return
  5. */
  6. public T newInstance(SqlSession sqlSession) {
  7. // 创建MapperProxy
  8. final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  9. return newInstance(mapperProxy);
  10. }
5. new MapperProxy(sqlSession, mapperInterface, methodCache)

通过MapperProxy构造方法创建MapperProxy对象。

  1. final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);

MapperProxy类实现了JDK中的InvocationHandler接口,InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

  1. /**
  2. * 构造方法
  3. * @param sqlSession SqlSession
  4. * @param mapperInterface mapper接口
  5. * @param methodCache 方法缓存
  6. */
  7. public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
  8. this.sqlSession = sqlSession;
  9. this.mapperInterface = mapperInterface;
  10. this.methodCache = methodCache;
  11. }
6. Proxy.newProxyInstance()

获取了基础的MapperProxy对象后,调用Proxy.newProxyInstance()方法通过反射技术创建mapper接口正真的JAVA动态代理对象。

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

总结

获取Mapper代理对象的流程很简单,大致就是通过Configuration对象中加载好的mapper接口信息,然后使用JDK动态代理,返回MapperProxy代理对象。
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,25人围观)

还没有评论,来说两句吧...

相关阅读