首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MyBatis 原始碼深度解析 (一):核心架構與執行流程總覽

     編輯:Java 相關知識

MyBatis 核心類別架構

SqlSessionFactoryBuilder
        ↓ build()
SqlSessionFactory (介面)
        ↓ openSession()
DefaultSqlSessionFactory → DefaultSqlSession (核心實作)
        ↓ 內部持有
Configuration (全域配置)
        ↓ 包含
MapperRegistry → MapperProxyFactory → MapperProxy (動態代理)
        ↓
Executor (執行器介面)
        ↓ 三種實作
BaseExecutor (抽象基類)
    ├── SimpleExecutor    (簡單執行)
    ├── ReuseExecutor     (重用 PreparedStatement)
    └── BatchExecutor     (批次執行)
        ↓
StatementHandler (語句處理器)
    ├── SimpleStatementHandler
    ├── PreparedStatementHandler
    └── CallableStatementHandler
        ↓
ParameterHandler / ResultSetHandler

核心流程:SqlSession 查詢執行

1. 入口:DefaultSqlSession.selectList()

public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        MappedStatement ms = configuration.getMappedStatement(statement);
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

2. 委派給 Executor

// BaseExecutor.query()
public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    // 1. 建立緩存鍵
    CacheKey key = createCacheKey(ms, parameter, rowBounds);
    
    // 2. 緩存查詢 (CachingExecutor 會攔截)
    List list = resultHandler == null ? (List) localCache.getObject(key) : null;
    if (list != null) return list;
    
    // 3. 實際查詢
    list = queryFromDatabase(ms, parameter, rowBounds, handler, key, boundSql);
    
    // 4. 存入本地緩存
    localCache.putObject(key, list);
    return list;
}

// 抽象方法留給子類實作
protected abstract  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
                                       ResultHandler handler, BoundSql boundSql);

3. SimpleExecutor 實作

public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
                          ResultHandler handler, BoundSql boundSql) {
    Statement stmt = null;
    try {
        Configuration config = ms.getConfiguration();
        // 1. 建立 StatementHandler
        StatementHandler handler = config.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        // 2. 準備 Statement (預編譯、設定參數)
        stmt = handler.prepare(connection, transaction.getTimeout());
        // 3. 執行查詢並處理結果集
        return handler.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

4. StatementHandler 責任鏈

// PreparedStatementHandler.query()
public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();  // 執行 SQL
    return resultSetHandler.handleResultSets(ps);  // 委派結果集處理
}

// ResultSetHandler.handleResultSets()
public List handleResultSets(Statement stmt) throws SQLException {
    List multipleResults = new ArrayList<>();
    int resultSetCount = 0;
    ResultSetWrapper rsw = new ResultSetWrapper(stmt.getResultSet(), configuration);
    List resultMaps = mappedStatement.getResultMaps();
    
    // 處理多結果集
    for (ResultMap resultMap : resultMaps) {
        multipleResults.add(handleResultSet(rsw, resultMap, null, null));
        if (stmt.getMoreResults()) {
            rsw = new ResultSetWrapper(stmt.getResultSet(), configuration);
        }
    }
    return multipleResults;
}


關鍵設計模式應用

模式應用場景核心類別
建造者模式SqlSessionFactory 建構SqlSessionFactoryBuilder, XMLConfigBuilder
工廠模式StatementHandler/Executor 建立Configuration.newStatementHandler()
模板方法BaseExecutor 定義查詢骨架query() → doQuery()
策略模式Executor 三種實作切換Simple/Reuse/BatchExecutor
代理模式Mapper 介面動態代理MapperProxy, MapperProxyFactory
責任鏈攔截器鏈InterceptorChain, Plugin
裝飾模式CachingExecutor 包裝 BaseExecutorCachingExecutor

配置解析流程

XMLConfigBuilder 解析 mybatis-config.xml

public Configuration parse() {
    // 1. 解析設定屬性
    parseConfiguration(rootNode);
    
    // 2. 解析類型別名
    typeAliasesElement(rootNode);
    
    // 3. 解析插件
    pluginElement(rootNode);
    
    // 4. 解析物件工廠/包裝工廠
    objectFactoryElement(rootNode);
    objectWrapperFactoryElement(rootNode);
    
    // 5. 解析設定值 (settings)
    settingsElement(rootNode);
    
    // 6. 解析環境 (數據源、事務管理器)
    environmentsElement(rootNode);
    
    // 7. 解析映射器 (Mapper XML 掃描)
    mapperElement(rootNode);
    
    return configuration;
}

XMLMapperBuilder 解析 Mapper XML

// 解析  節點
private void buildStatementFromContext(List list, String requiredDatabaseId) {
    for (XNode context : list) {
        XMLStatementBuilder stmtBuilder = new XMLStatementBuilder(configuration, context, null);
        try {
            stmtBuilder.parseStatementNode();  // 核心解析邏輯
        } catch (IncompleteElementException e) {
            configuration.addIncompleteStatement(stmtBuilder);
        }
    }
}

BoundSql 動態 SQL 產生

// DynamicSqlSource.getBoundSql()
public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);  // OGNL 表達式評估、 等標籤處理
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    return sqlSource.getBoundSql(parameterObject);
}

下篇預告

  • 攔截器機制與分頁插件實作原理
  • 緩存架構:一級/二級緩存、CacheKey 設計
  • 類型處理器 TypeHandler 體系
  • 事務管理與 Spring 整合原理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved