美文网首页
mybatis 接口依赖注入源码分析

mybatis 接口依赖注入源码分析

作者: 瞿大官人 | 来源:发表于2019-03-21 18:46 被阅读0次

    前言

    上次讲了mybatis 中Mapper注入spring源码分析,实质就是如何将一个接口放入Spring工厂中,有放就有取,因此这次介绍的是mybatis是如何从Spring工厂中取出相应的Mapper

    源码分析

    MapperRegistry:以Mapper.class为key,MapperProxyFactory对象为value,对外用于生产Mapper接口对应的代理对象。
    MapperProxyFactory:作用生产对应的Mapper代理。
    MapperProxy:实现了InvocationHandler 接口,代理类。
    MapperFactoryBean:获得代理对象,将其提供给Spring

    image.png

    现在我们以上图为标准,从MapperFactoryBean开始一一分析源码。

    MapperFactoryBean

    其实在上一节已经提示过,这个类很重要。


    image.png

    以下是MapperFactoryBean的源码,其实代码还是比较简单的,不过这个类是连接Springmybatis的桥梁,Spring通过调用这个类的getObject()方法实例化代理对象,然后将其注入到Mapper上。

    // 这是一个FactoryBean类
    public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    
      private Class<T> mapperInterface;
    
      public MapperFactoryBean() {
        
      }
      //Spring实例化这个类,就是通过这个构造函数,mapperInterface 就是Mapper接口的class对象
      // 参数就是上一张截图中的xxxxx.addGenericArgumentValue(xxxxx)
      public MapperFactoryBean(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
      }
    
      /**
       * {@inheritDoc}
       */
      @Override
      protected void checkDaoConfig() {
        super.checkDaoConfig();
    
        Configuration configuration = getSqlSession().getConfiguration();
        if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
          try {
            //configuration 底层调用MapperRegistry类将mapperInterface保存起来,以便调用
            //getObject() 方法的时候能够获取Mapper接口对应的代理类。
            configuration.addMapper(this.mapperInterface);
          } catch (Exception e) {
        }
      }
    /**
    * 获取Mapper接口对应的代理类对象,后面依赖Mapper接口注入的对象就是这个代理对象。
    这个方法的调用是在AbstractBeanFactory对象里面。具体到方法是getObjectForBeanInstance
    **/
      @Override
      public T getObject() throws Exception {
      // 生成代理对象的调用链路
      // SqlSession -->Configuration-->MapperRegistry-->MapperProxyFactory->MapperProxy
        return getSqlSession().getMapper(this.mapperInterface);
      }
    
      @Override
      public Class<T> getObjectType() {
        return this.mapperInterface;
      }
      @Override
      public boolean isSingleton() {
        return true;
      }
    }
    

    DefaultSqlSession

    public class DefaultSqlSession implements SqlSession{
      private final Configuration configuration;
    ....
      @Override
      public <T> T getMapper(Class<T> type) {
        return configuration.<T>getMapper(type, this);
      }
    ...
    }
    

    Configuration

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

    MapperRegistry

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

    MapperProxyFactory

    两个newInstance方法都是生成代理对象。

    public class MapperProxyFactory<T> {
    
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
    
      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, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    
    }
    

    MapperProxy

    了解下Java的动态代理就知道了。

    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;
      }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
          } else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        // 执行sql 操作。
        return mapperMethod.execute(sqlSession, args);
      }
    }
    

    总结

    这节本质就是动态代理+FactoryBean实现接口代理能够依赖注入。理论将了两节,下一节将动手实现接口放入spring工厂,以及能够依赖注入。

    相关文章

      网友评论

          本文标题:mybatis 接口依赖注入源码分析

          本文链接:https://www.haomeiwen.com/subject/oyafvqtx.html