大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動(dòng)力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 MyBatis源碼分析

MyBatis源碼分析

更新時(shí)間:2022-06-27 10:33:59 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2051次

配置解析

Java教程中,MyBatis是學(xué)習(xí)課程之一,MyBatis 的初始化以及執(zhí)行一條 SQL 語句的全流程中也包含了配置解析,我們?cè)诂F(xiàn)實(shí)開發(fā)中一般都是使用spring boot starter的自動(dòng)配置。我們一項(xiàng)目啟動(dòng)為起點(diǎn)一層一層剝開Mybatis的流程。先打開org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration首先明確一點(diǎn)就是MybatisAutoConfiguration的目的就是要得到一個(gè)SqlSessionFactory。

??@Bean
??@ConditionalOnMissingBean
??public?SqlSessionFactory?sqlSessionFactory(DataSource?dataSource)?throws?Exception?{
????SqlSessionFactoryBean?factory?=?new?SqlSessionFactoryBean();
????factory.setDataSource(dataSource);
????factory.setVfs(SpringBootVFS.class);
????if?(StringUtils.hasText(this.properties.getConfigLocation()))?{
??????factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
????}
????Configuration?configuration?=?this.properties.getConfiguration();
????if?(configuration?==?null?&&?!StringUtils.hasText(this.properties.getConfigLocation()))?{
??????configuration?=?new?Configuration();
????}
????if?(configuration?!=?null?&&?!CollectionUtils.isEmpty(this.configurationCustomizers))?{
??????for?(ConfigurationCustomizer?customizer?:?this.configurationCustomizers)?{
????????customizer.customize(configuration);
??????}
????}
????factory.setConfiguration(configuration);
????if?(this.properties.getConfigurationProperties()?!=?null)?{
??????factory.setConfigurationProperties(this.properties.getConfigurationProperties());
????}
????if?(!ObjectUtils.isEmpty(this.interceptors))?{
??????factory.setPlugins(this.interceptors);
????}
????if?(this.databaseIdProvider?!=?null)?{
??????factory.setDatabaseIdProvider(this.databaseIdProvider);
????}
????if?(StringUtils.hasLength(this.properties.getTypeAliasesPackage()))?{
??????factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
????}
????if?(StringUtils.hasLength(this.properties.getTypeHandlersPackage()))?{
??????factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
????}
????if?(!ObjectUtils.isEmpty(this.properties.resolveMapperLocations()))?{
??????factory.setMapperLocations(this.properties.resolveMapperLocations());
????}
????return?factory.getObject();
??}

這里是通過MybatisProperties里面的配置并放入到SqlSessionFactoryBean中,再由SqlSessionFactoryBean得到SqlSessionFactory。看到最后一行return factory.getObject();我們進(jìn)去看看這個(gè)factory.getObject()的邏輯是如何得到一個(gè)SqlSessionFactory。

@Override
public SqlSessionFactory getObject() throws Exception {
  if (this.sqlSessionFactory == null) {
    afterPropertiesSet();
  }
  return this.sqlSessionFactory;
}

看看afterPropertiesSet()方法

@Override
public void afterPropertiesSet() throws Exception {
  notNull(dataSource, "Property 'dataSource' is required");
  notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
  state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
            "Property 'configuration' and 'configLocation' can not specified with together");
  this.sqlSessionFactory = buildSqlSessionFactory();
}

重點(diǎn)來了,看看這個(gè)buildSqlSessionFactory()方法這里的核心目的就是將configurationProperties解析到Configuration對(duì)象中。代碼太長了就不貼出來了, buildSqlSessionFactory()的邏輯我畫了個(gè)圖,有興趣的小伙伴自行看一下。

Mybatis配置解析1

我們不要陷入細(xì)節(jié)之中,我們看看中點(diǎn)看看buildSqlSessionFactory() 方法的最后一行this.sqlSessionFactoryBuilder.build(configuration)點(diǎn)進(jìn)去

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

通過buildSqlSessionFactory()解析得到的Configuration對(duì)象創(chuàng)建一個(gè)DefaultSqlSessionFactory(config),到此我們就得到了SqlSessionFactory同時(shí)被配置成一個(gè)bean了。

我們最終操作都是SqlSession,什么時(shí)候會(huì)通過SqlSessionFactory得到一個(gè)SqlSession呢?

要解決這個(gè)問題我們回到最開始的MybatisAutoConfiguration的sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)這個(gè)方法,點(diǎn)開SqlSessionTemplate發(fā)現(xiàn)它是一個(gè)實(shí)現(xiàn)了SqlSession到這里我們猜測就是在這里SqlSessionFactory會(huì)構(gòu)建一個(gè)SqlSession出來。我們進(jìn)入new SqlSessionTemplate(sqlSessionFactory)看看源碼。

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
  }

再往下看,我們就看到了

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
    PersistenceExceptionTranslator exceptionTranslator) {
  notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
  notNull(executorType, "Property 'executorType' is required");
  this.sqlSessionFactory = sqlSessionFactory;
  this.executorType = executorType;
  this.exceptionTranslator = exceptionTranslator;
  this.sqlSessionProxy = (SqlSession) newProxyInstance(
      SqlSessionFactory.class.getClassLoader(),
      new Class[] { SqlSession.class },
      new SqlSessionInterceptor());
}

這里通過動(dòng)態(tài)代理創(chuàng)建了一個(gè)SqlSession。

參數(shù)映射、SQL解析

我們先看一下MapperFactoryBean類,這個(gè)類實(shí)現(xiàn)了FactoryBean在bean初始化的時(shí)候會(huì)調(diào)用getObject()方法我們看看這個(gè)類下重寫的getObject()方法里的內(nèi)容。

 @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

這里調(diào)用了sqlSession的getMapper()方法。一層一層點(diǎn)進(jìn)去里面返回的是一個(gè)代理對(duì)象。最后的執(zhí)行是由MapperProxy執(zhí)行。

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);
    }
  }

接下來的流程還是畫個(gè)流程圖,防止小伙伴們走丟。

Mybatis參數(shù)綁定

先看一下MapperProxy中的invoke方法,cachedMapperMethod()方法將MapperMethod緩存起來了。

@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);
  return mapperMethod.execute(sqlSession, args);
}
 private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

我們?cè)谕驴磎apperMethod.execute(sqlSession, args)方法。

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);
      }
      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;
}

method.convertArgsToSqlCommandParam(args)這里就是處理參數(shù)轉(zhuǎn)換的邏輯。還有很多細(xì)節(jié)由于篇幅有限以及時(shí)間倉促我們不做過多的贅述,感興趣的小伙伴可以結(jié)合上面的圖自己看看。下面我們看SQL的執(zhí)行流程是怎么樣的。整體流程如下圖。

Mybatis執(zhí)行流程

我們就不對(duì)每一個(gè)執(zhí)行器都分析,我只挑一個(gè)SimpleExecutor來具體跟一下源碼。我們還是先看看圖吧,防止自己把自己搞蒙。

以simpleExecutor為例的執(zhí)行流程

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.<E>query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

這里獲取了Configuration,創(chuàng)建了一個(gè)StatementHandler,預(yù)處理操作,具體執(zhí)行的根據(jù)創(chuàng)建的預(yù)處理方法,最后執(zhí)行query方法

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  String sql = boundSql.getSql();
  statement.execute(sql);
  return resultSetHandler.<E>handleResultSets(statement);
}

以上就是關(guān)于“MyBatis源碼分析”的介紹,大家如果對(duì)此比較感興趣,想了解更多相關(guān)知識(shí),可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的Mybatis視頻教程,里面的課程內(nèi)容由淺到深,細(xì)致全面,通俗易懂,適合小白學(xué)習(xí),希望對(duì)大家能夠有所幫助。

提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 国产精品亚洲第一区广西莫菁 | 手机看片精品高清国产日韩 | 四虎成人免费网址在线 | 久久综合图区亚洲综合图区 | 妖精视频一区二区三区 | 色丁香六月 | 四虎新网站 | 九九热视频这里只有精品 | 黄色毛片视频 | 伊人久久免费视频 | 精品国产一区二区三区www | 国产精品18 | se94se亚洲欧美在线 | 九月丁香婷婷亚洲综合色 | 最新男同志freevideos | 在线a人片免费观看国产 | 有码中文字幕在线观看 | 国产一区二区精品久 | 欧美日韩亚洲一区二区三区 | 亚洲精品久久久久综合网 | 欧美va放荡人妇大片 | 奇米影视222| 999精品视频在线观看 | 不卡视频在线播放 | 国产在线日韩 | 日本岛国片在线观看 | 欧美精品在线播放 | 热久久在线观看 | 国产精品边做奶水狂喷小说 | 久久伊人影视 | 国产在线看不卡一区二区 | 四虎免费网址 | 亚洲精品成人久久 | 亚洲视频在线一区二区三区 | 天天色综合天天 | 天天操夜夜操夜夜操 | 全免费a级毛片免费看不卡 全免费a级毛片免费看视频免 | 五月婷婷久 | 五月婷在线视频 | 成人毛片网站 | www.伊人.com|