【Mybatis】源码分析简单记录(版本3.5.16)

一、代码实例1

public class Main {

    /**
     * 通过java.lang.System#setProperty方法设置系统属性
     * cglib.debugLocation=指定的字节码输出目录
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        System.setProperty("cglib.debugLocation", "./");
        //1.加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //2.获取sqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.获取sqlSession会话对象
        InvocationHandler dd;
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Connection connection= sqlSession.getConnection();

        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user=new User();
        user.setUserId(1);
        user.setUserName("zhongguochongqing");
        user.setDeptName("测试");
        user.setRealName("太阳");
        user.setPassword("123456");
        int res=userMapper.insert(user);
        sqlSession.commit();
        sqlSession.close();
        System.out.println(res);

    }


}

1、看下怎么构建SqlSessionFactory

new SqlSessionFactoryBuilder() 是一个默认构造函数,没有什么好看的。

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      ///解析mybatis的全部配置信息
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      ///parser.parse() 解析成一个Configuration 里面所有的信息都在里面了
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        if (inputStream != null) {
          inputStream.close();
        }
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
  
 public SqlSessionFactory build(Configuration config) {
    //最后构造一个默认的SqlSessionFactory 实现类对象
    return new DefaultSqlSessionFactory(config);
  }
 //直接把配置信息赋值给了一个属性
 public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

2、然后看sqlSession = sqlSessionFactory.openSession();

///开始获取一个sqlSession
public SqlSession openSession(boolean autoCommit) {
    ///这里要获取一个 默认的ExecutorType,ExecutorType是一个枚举: SIMPLE REUSE BATCH
    //当前默认返回 SIMPLE
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
  }

  //然后进入openSessionFromDataSource 方法
 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
      boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      ///根据配置信息获取一个 事务工厂,这个工厂就是
      ///为后面创建一个具体的事务,后面再看看具体它是怎么创建这个事务工厂的 todo
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      ///然后创建了一个事务对象因为后面执行sql肯定是要用到事务的,
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      ///然后构造一个simple类型的Executor,
      //如果设置了拦截器的话就会返回这个执行器的代理对象
      final Executor executor = configuration.newExecutor(tx, execType);
      ///构造一个 sqlSession,可以看到这个sqlSession里面是有 全局配置对象,执行器,和有关事务
      //提交相关的信息 autoCommit
      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();
    }
  }

 ///当前this =configuration ,这里是构造 Executor的详细步骤,里面也比较简单,就是把
//配置对象 和事务对象传入,根据前面的executorType 构造指定的执行器
 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    ///mybatis默认缓存时有效的,这里就用缓存执行器 包装了下原始的执行器,
    ///因为在mybatis中一级缓存时在executor里面的
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    ///这里是给执行器 安装拦截器
    return (Executor) interceptorChain.pluginAll(executor);
  }
///SimpleExecutor 是BaseExecutor的子类,最终SimpleExecutor的构造函数也会调用这个
//具体内容如下:
protected BaseExecutor(Configuration configuration, Transaction transaction) {
    //设置下事务对象
    this.transaction = transaction;
    ///初始化延迟加载的 缓队列
    this.deferredLoads = new ConcurrentLinkedQueue<>();
    //设置下缓存
    this.localCache = new PerpetualCache("LocalCache");
    this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
    this.closed = false;
    this.configuration = configuration;
    //this.warpper 就是simpleExecutor
    this.wrapper = this;///这是一个simpleExecutor的自引用
  }

结论:

    从上面的代码得出的一些重要信息是:  在构造sqlSession时就只是一些简单的创建一些对象,然后赋值下而已,构建sqlSession对象时会构造: 临时的事务工厂然后构造一个事务对象,也会创建一个Executor对象,同时这个对象会用CacheExecutor包装下。就是说在创建SqlSession对象时或创建几个重要对象,且这些对象是和SqlSession关联的,然后就是给执行器添加拦截器

    a: 事务对象    b: 执行器executor ,事务对象是在执行器中

3、然后看看拦截器的添加过程

///首先这个方法是 interceptorChain对象的,而interceptorChain是在 全局配置对象中的属性,
//在解析配置的时候创建的interceptorChain
 public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      ///调用拦截器的 plugin方法,这里就是生成target(此时是Executor)
      target = interceptor.plugin(target);
    }
    return target;
  }
///这个是自定义的一个拦截器MyExecutorInterceptor 的plugin方法,这里什么都没有做
//就是返回原始的Executor
@Override
public Object plugin(Object target) {
   System.out.println("MyExecutorInterceptor-plugin");
   return target;
}

4、然后看看UserMapper userMapper=sqlSession.getMapper(UserMapper.class); 

///DefaultSqlSession 的方法,Type是具体Mapper的接口类
//Mapper还是有全局配置对象来构建  
public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
  }
  ///进入configuration.getMapper,里面有一个mapper注册器MapperRegistry
//这个mapper注册器中有 
 //Map<Class<?>, MapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>();
//Class 就是我们自定义的Mapper接口类,对应的时这个mapper的动态代理 创建工厂
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
  ///具体进入MapperRegistry.getMapper 方法中。
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //从缓存中获取一个 代理工厂,应是在 解析配置文件的时候就创建好了
    //每一个Mapper接口都对应一个代理工厂,代理工厂中有UserMapper这个接口Class对象,同时
//还有 Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
//这个接口定义的所有方法的执行器缓存Map

    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      ///用工厂创建一个UserMapper接口的 MapperProxy型的代理对象。就是用jdk代理的方式
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
  ///return mapperProxyFactory.newInstance(sqlSession);的方法如下
  public T newInstance(SqlSession sqlSession) {
    ///这个MapperProxy 是一个InvocationHandler 用来生成代理的,它有几个重要属性
//1. 当前UserMappr接口Class,还有sqlSession
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    ///然后创建一个mapperProxy 代理,代理对象实现了UserMapper接口,里面的InvocationHandler 就是mapperProxy 本身,最后调用UserMapper的方法都是会调用这个代理
    return newInstance(mapperProxy);
  }
   






上面的代码主要是 获取UserMapper接口的jdk实现的动态代理类,具体代码内容可以查看:【JDK动态代理】以下是mybatis生产一个Mapper接口动态代理类-CSDN博客

5、下面就是执行数据库操作

    ///首先进入UserMapper 的代理类的 insert方法
    public final int insert(User var1) {
        try {
            ///super.h 就是上面的mapperProxy对象 ,然后调用者mapperProxy的invoker
            //this就是当前代理对象本身,m4就是UserMapper接口的insert方法Method对象
            return (Integer)super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
  ///然后进入mapperProxy 的invoke的方法中
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      ///如果是Object类的方法 就不拦截
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      }
      ///然后用cachedInvoker封装method,返回一个MapperMethodInvoker(默认PlainMethodInvoker) 在调用MapperMethodInvoker 的invoker
      return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

///调用invoker后面会进入MapperMethod的execute方法
 public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        ///解析参数 里面由ParamNameResolver类解析参数
        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());
    }

后面会进入 DefaultSqlSession 中的update方法
///这里才开始用执行器 
 public int update(String statement, Object parameter) {
    try {
      dirty = true;
      //通过org.bqs.mapper.UserMapper.insert 获取到对应的MappedStatement 
      ///MappedStatement里面封装了要执行的sql语句相关的信息,它对应的
      //就是mapper.xml文件中的 一个sql配置
      MappedStatement ms = configuration.getMappedStatement(statement);
      ///在创建sqlSession时创建的executor 开始执行
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  后面来到SimpleExecutor 的doUpdate方法中
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    //这是一个jdbc的Statement
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
       ///利用全局配置 创建一个StatementHandler 默认是 RoutingStatementHandler 然后内部要包含了具体的 PreparedStatementHandler ,要是一个静态代理模式,由于我加了拦截器 ,当前返回的时一个代理对象StatementHandler 
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      ///利用StatementHandler 类执行jdbc的Statement 具体内容是啥
     //
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

  configuration.newStatementHandler 方法
  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
      Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
     ///返回一个StatementHandler  它里面封装了 Executor,ParameterHandler ResultSetHandler 还有BoundSql   MapperedStatement
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
        rowBounds, resultHandler, boundSql);
    ///处理StatementHandler类型的拦截器
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
  }

6、看看StatementHandler 具体做了啥

  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    }
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.prepareStatement(sql);
    } else {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(),
          ResultSet.CONCUR_READ_ONLY);
    }
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值