缩略图

MyBatis源码深度解析:架构设计与核心机制剖析

2025年10月16日 文章分类 会被自动插入 会被自动插入
本文最后更新于2025-10-16已经过去了44天请注意内容时效性
热度41 点赞 收藏0 评论0

MyBatis源码深度解析:架构设计与核心机制剖析

引言

MyBatis作为Java领域最受欢迎的持久层框架之一,自问世以来就以其灵活性和高性能著称。与传统的Hibernate等全自动ORM框架不同,MyBatis采用半自动化的数据映射方式,在保持SQL灵活性的同时,极大地简化了数据库操作。本文将深入MyBatis源码,从架构设计、核心组件、执行流程等多个维度进行全面解析,帮助开发者深入理解MyBatis的内部机制。

一、MyBatis整体架构设计

1.1 三层架构模型

MyBatis采用了经典的三层架构设计,分别是基础支撑层、核心处理层和接口层。

基础支撑层包含了整个框架的基础功能模块:

  • 类型转换模块(Type Handler)
  • 日志模块(Logging)
  • 资源加载模块(Resources)
  • 解析器模块(Parser)
  • 数据源模块(DataSource)
  • 事务管理模块(Transaction)
  • 缓存模块(Cache)
  • 绑定模块(Binding)

核心处理层是MyBatis框架的核心,主要包括:

  • 配置解析(Configuration)
  • SQL解析(SqlSource)
  • SQL执行(Executor)
  • 结果集映射(ResultSetHandler)
  • 参数映射(ParameterHandler)

接口层提供了面向用户的高级API:

  • SqlSession
  • Mapper接口
  • Mapper注解

1.2 核心组件协作关系

MyBatis的核心组件之间通过精密的协作完成整个数据库操作流程。SqlSession作为门面接口,接收用户请求并委托给Executor执行;Executor通过StatementHandler操作JDBC Statement对象;ParameterHandler负责参数映射;ResultSetHandler处理结果集映射。

二、配置解析机制深度解析

2.1 Configuration类的核心作用

Configuration类是MyBatis的核心配置容器,采用单例模式设计,在整个应用生命周期中只存在一个实例。它负责存储和管理所有的配置信息:

public class Configuration {
    protected Environment environment;
    protected final Map<String, MappedStatement> mappedStatements = new StrictMap<>("Mapped Statements collection");
    protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
    protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
    protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
}

2.2 XML配置解析过程

MyBatis通过XMLConfigBuilder解析主配置文件,这个过程涉及多个解析器的协作:

public class XMLConfigBuilder extends BaseBuilder {
    public Configuration parse() {
        if (parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
    }

    private void parseConfiguration(XNode root) {
        try {
            propertiesElement(root.evalNode("properties"));
            Properties settings = settingsAsProperties(root.evalNode("settings"));
            loadCustomVfs(settings);
            typeAliasesElement(root.evalNode("typeAliases"));
            pluginElement(root.evalNode("plugins"));
            objectFactoryElement(root.evalNode("objectFactory"));
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            reflectorFactoryElement(root.evalNode("reflectorFactory"));
            settingsElement(settings);
            environmentsElement(root.evalNode("environments"));
            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            typeHandlerElement(root.evalNode("typeHandlers"));
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    }
}

2.3 映射文件解析细节

映射文件的解析由XMLMapperBuilder负责,重点在于SQL语句的解析和MappedStatement的构建:

public class XMLMapperBuilder extends BaseBuilder {
    private void buildStatementFromContext(List<XNode> list) {
        if (configuration.getDatabaseId() != null) {
            buildStatementFromContext(list, configuration.getDatabaseId());
        }
        buildStatementFromContext(list, null);
    }

    private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
        for (XNode context : list) {
            final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
            try {
                statementParser.parseStatementNode();
            } catch (IncompleteElementException e) {
                configuration.addIncompleteStatement(statementParser);
            }
        }
    }
}

三、SqlSession执行流程剖析

3.1 SqlSession的创建过程

SqlSession的创建通过SqlSessionFactory完成,DefaultSqlSession是默认实现:

public class DefaultSqlSession implements SqlSession {
    private final Configuration configuration;
    private final Executor executor;
    private final boolean autoCommit;
    private boolean dirty;
    private List<Cursor<?>> cursorList;

    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }
}

3.2 SQL执行的核心链路

SQL执行的核心链路涉及多个组件的协作:

  1. SqlSession接收请求:用户调用selectOne、selectList等方法
  2. Executor执行查询:根据配置选择不同的Executor实现
  3. StatementHandler处理Statement:创建并配置PreparedStatement
  4. ParameterHandler设置参数:将Java参数转换为JDBC参数
  5. ResultSetHandler处理结果:将ResultSet转换为Java对象
public class DefaultSqlSession implements SqlSession {
    @Override
    public <E> List<E> 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();
        }
    }
}

四、Executor执行器机制详解

4.1 执行器类型与选择策略

MyBatis提供了三种执行器实现:

SimpleExecutor:最简单的执行器,每次执行都会创建新的Statement对象 ReuseExecutor:重用预处理语句的执行器 BatchExecutor:批处理执行器

执行器的选择通过配置决定:

public enum ExecutorType {
    SIMPLE, REUSE, BATCH
}

4.2 二级缓存与执行器装饰

CachingExecutor是Executor的装饰器,为其他执行器添加二级缓存功能:

public class CachingExecutor implements Executor {
    private final Executor delegate;
    private final TransactionalCacheManager tcm = new TransactionalCacheManager();

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();
        if (cache != null) {
            flushCacheIfRequired(ms);
            if (ms.isUseCache() && resultHandler == null) {
                ensureNoOutParams(ms, boundSql);
                @SuppressWarnings("unchecked")
                List<E> list = (List<E>) tcm.getObject(cache, key);
                if (list == null) {
                    list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    tcm.putObject(cache, key, list);
                }
                return list;
            }
        }
        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
}

4.3 延迟加载机制

MyBatis通过Javassist或CGLIB实现延迟加载,主要涉及ProxyFactory和LazyLoader:


public class JavassistProxyFactory implements ProxyFactory {
    @Override
    public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
    }

    private static class EnhancedResultObjectProxyImpl implements MethodHandler {
        @Override
        public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
            final String methodName = method.getName();
            try {
                synchronized (lazyLoader) {
                    if (WRITE_REPLACE_METHOD.equals(methodName)) {
                        Object original = null;
                        if (constructorArgTypes.isEmpty()) {
                            original = objectFactory.create(type);
                        } else {
                            original = objectFactory.create(type, constructorArgTypes, constructorArgs);
                        }
                        PropertyCopier.copyBeanProperties(type, enhanced, original);
                        return original;
                    } else {
                        if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
                            lazyLoader.loadAll();
                        }
                    }
                }
                return methodProxy.invoke(enhanced,
正文结束 阅读本文相关话题
相关阅读
评论框
正在回复
评论列表

暂时还没有任何评论,快去发表第一条评论吧~

空白列表
sitemap