mybaits 源码分析4

MyBatis 中 查看源码, 首先是SqlSessionFactoryBuilder 创建出SqlSessionFactory,然后从SqlSessionFactory中得到SqlSession,最后通过SqlSession得到Mapper接口对象进行数据库操作

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

通过跟踪SqlSessionFactoryBuilder源码

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
  try {
     // 通过XMLConfigBuilder 类进行解析 传进来的  mybatis-config.xml 配置文件
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    // 解析之后,把值传给build方法
    return build(parser.parse());
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  } finally {
    ErrorContext.instance().reset();
    try {
      inputStream.close();
    } catch (IOException e) {
      // Intentionally ignore. Prefer previous error.
    }
  }
}

然后 在通过 XMLConfigBuilder 对读取mybatis-config.xml的文件进行解析,然后 调用 DefaultSqlSessionFactory 

public SqlSessionFactory build(Configuration config) {
  return new DefaultSqlSessionFactory(config);
}

继续往下跟,DefaultSqlSessionFactory 的 openSession()方法,参数 是  Configuration 对象

private final Configuration configuration;

public DefaultSqlSessionFactory(Configuration configuration) {
  this.configuration = configuration;
}

再通过构造方法把值传给Configuration 对象解析解析,接下来我们看看Configuration对象类,内容太多了,把主要列出来 ,看看 这个 接口都干了什么

public class Configuration {

 protected Environment environment;
protected Class<?> configurationFactory;

protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

}

看看熟悉不熟悉,这个里面 的 Envirobnment 这个 就是为了解析 mybatis-config.xml 中的标签<configuration>,这个就是  MapperRegistry 这都是 把我们写mapper接口进行注册绑定

 通过上面我们阅读源码 调用openSessionFromDataSource()方法,方面里面执行解析配置文件,而且都定义为final类型,说明这个方法只在程序刚运行的时候加载一次

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    final Executor executor = configuration.newExecutor(tx, execType);
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {
    closeTransaction(tx); // may have fetched a connection so lets call close()
    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

接下来继续看通过sqlSessionFactory创建SqlSession获取getMapper,参数为繁星目标对象,

/**
 * Retrieves a mapper.
 * @param <T> the mapper type
 * @param type Mapper interface class
 * @return a mapper bound to this SqlSession
 */
<T> T getMapper(Class<T> type);

看这个类的实现类方法,返回的是通过configuration对象中在去获取getMapper的

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

在继续跟configuration.getMapper(type, this); 看看这就是通过刚才上面对配置文件加载注册到 MapperRegistry对象中,

在通过 mapperRegistry.getMapper(type, sqlSession)来获取注册过绑定的接口

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

继续跟进 mapperRegistry.getMapper(type, sqlSession);实现如下,看到如下枉然大悟,

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //通过MapperProxyFactory<T>对象获取type
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    //判断配置文件中有没有,先前注册好的 mapper接口,要是没有就是报错
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
     //要是有之前mapper 注册过的 接口,就会在这里生成一个新的实例 mapperProxyFactory.newInstance(sqlSession);
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

看看MapperProxyFactory 对象,通过jdk代理生成

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

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

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

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

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
     //看看这代码熟悉不,这就是平时所用的jdk 代码
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
     //生成新的实例对象,以及缓存
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

分析 MapperProxy代理类,跟进去首先是一个带参构造方法,如下:

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

然后还有 invoke方法

@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 (method.isDefault()) {
      return invokeDefaultMethod(proxy, method, args);
    }
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
   //从缓存mapper方法中寻找
  final MapperMethod mapperMethod = cachedMapperMethod(method);
   //然后执行mapperMethod.execute(sqlSession, args)
  return mapperMethod.execute(sqlSession, args);
}

在来看看 mapperMethod.execute(sqlSession, args) ,这个方法就是最终判断传入是

INSERT、UPDATE、DELETE 、SELECT 等判断, 决定执行sql语句

public Object execute(SqlSession sqlSession, Object[] args) {
  Object result;
  switch (command.getType()) {
    case INSERT: {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
      break;
    }
    case UPDATE: {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
      break;
    }
    case DELETE: {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
      break;
    }
    case SELECT:
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else if (method.returnsCursor()) {
        result = executeForCursor(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
        if (method.returnsOptional()
            && (result == null || !method.getReturnType().equals(result.getClass()))) {
          result = Optional.ofNullable(result);
        }
      }
      break;
    case FLUSH:
      result = sqlSession.flushStatements();
      break;
    default:
      throw new BindingException("Unknown execution method for: " + command.getName());
  }
  if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
    throw new BindingException("Mapper method '" + command.getName()
        + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  }
  return result;
}

然后在把查询数据库的result ,返回回去,这就是mybatis 一个完整的执行过程

猜你喜欢

转载自blog.csdn.net/CHL123456789/article/details/101206589
今日推荐