MyBatis 源码深度解析

MyBatis 源码深度解析

一、整体架构设计

MyBatis采用清晰的分层架构设计,主要分为三层:

  1. 接口层:提供SQL操作API(SqlSession、Mapper接口)
  2. 核心处理层:负责SQL解析、参数映射、SQL执行、结果映射
  3. 基础支撑层:提供连接管理、事务管理、缓存、日志等基础设施

这种分层设计使得MyBatis的各个组件职责明确,耦合度低,便于扩展。

二、核心组件源码详解

2.1 SqlSessionFactory 与初始化流程

SqlSessionFactory是MyBatis的核心工厂类,负责创建SqlSession实例。其主要实现类为DefaultSqlSessionFactory。

java 复制代码
// SqlSessionFactory接口定义
public interface SqlSessionFactory {
    SqlSession openSession();
    SqlSession openSession(boolean autoCommit);
    SqlSession openSession(Connection connection);
    SqlSession openSession(TransactionIsolationLevel level);
    // 其他方法...
}

// DefaultSqlSessionFactory核心实现
public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;
    
    public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
    }
    
    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);
        }
    }
}

初始化过程:

  1. SqlSessionFactoryBuilder.build()方法解析配置文件,构建Configuration对象
  2. 解析全局配置、mapper映射、别名、插件等信息
  3. 注册映射语句(MappedStatement)到Configuration中
  4. 创建并返回SqlSessionFactory实例

2.2 SqlSession 实现机制

SqlSession是应用与MyBatis交互的核心接口,代表一次数据库会话。其默认实现为DefaultSqlSession。

java 复制代码
// SqlSession接口
public interface SqlSession extends Closeable {
    <T> T selectOne(String statement);
    <T> T selectOne(String statement, Object parameter);
    <E> List<E> selectList(String statement);
    <E> List<E> selectList(String statement, Object parameter);
    // 其他查询方法...
    int insert(String statement);
    int insert(String statement, Object parameter);
    int update(String statement);
    int update(String statement, Object parameter);
    int delete(String statement);
    int delete(String statement, Object parameter);
    void commit();
    void rollback();
    <T> T getMapper(Class<T> type);
    void close();
}

// DefaultSqlSession核心实现
public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;
    private Executor executor;
    private boolean autoCommit;
    private boolean dirty;
    
    @Override
    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }
    
    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }
    
    @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();
        }
    }
}

2.3 Executor 执行器体系

Executor是MyBatis的核心执行器,负责SQL语句的执行和缓存管理。MyBatis提供了多种Executor实现:

  1. BaseExecutor:所有执行器的抽象基类,提供通用功能
  2. SimpleExecutor:默认执行器,每次执行SQL都创建新的Statement
  3. ReuseExecutor:重用执行器,会缓存Statement
  4. BatchExecutor:批处理执行器,优化批量操作
  5. CachingExecutor:缓存执行器,提供二级缓存支持
java 复制代码
// Executor接口
public interface Executor {
    ResultHandler NO_RESULT_HANDLER = null;
    
    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
    int update(MappedStatement ms, Object parameter) throws SQLException;
    void commit(boolean required) throws SQLException;
    void rollback(boolean required) throws SQLException;
    // 其他方法...
}

// SimpleExecutor核心实现
public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }
    
    @Override
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
            Configuration config = ms.getConfiguration();
            // 创建StatementHandler
            StatementHandler handler = config.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 准备Statement
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 执行查询
            return handler.query(stmt, resultHandler);
        } finally {
            closeStatement(stmt);
        }
    }
    
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);
        stmt = handler.prepare(connection, transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
    }
}

2.4 StatementHandler 与 SQL 执行

StatementHandler负责处理JDBC的Statement操作,包括创建Statement、设置参数、执行SQL等。MyBatis提供了三种实现:

  1. SimpleStatementHandler:对应JDBC的Statement
  2. PreparedStatementHandler:对应JDBC的PreparedStatement
  3. CallableStatementHandler:对应JDBC的CallableStatement
java 复制代码
// StatementHandler接口
public interface StatementHandler {
    Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
    void parameterize(Statement statement) throws SQLException;
    void batch(Statement statement) throws SQLException;
    int update(Statement statement) throws SQLException;
    <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
    <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
    BoundSql getBoundSql();
    ParameterHandler getParameterHandler();
}

// PreparedStatementHandler核心实现
public class PreparedStatementHandler extends BaseStatementHandler {
    
    public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
    }
    
    @Override
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement(boundSql.getSql(), mappedStatement.getStatementType());
            setStatementTimeout(ps, transactionTimeout);
            setFetchSize(ps);
            return ps;
        } catch (SQLException e) {
            closeStatement(ps);
            throw e;
        } catch (Exception e) {
            closeStatement(ps);
            throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
    }
    
    @Override
    public void parameterize(Statement statement) throws SQLException {
        parameterHandler.setParameters((PreparedStatement) statement);
    }
    
    @Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute();
        return resultSetHandler.handleResultSets(ps);
    }
}

2.5 ParameterHandler 参数处理

ParameterHandler负责处理SQL语句中的参数,设置PreparedStatement的参数值。

java 复制代码
// ParameterHandler接口
public interface ParameterHandler {
    Object getParameterObject();
    void setParameters(PreparedStatement ps) throws SQLException;
}

// DefaultParameterHandler实现
public class DefaultParameterHandler implements ParameterHandler {
    private final TypeHandlerRegistry typeHandlerRegistry;
    private final MappedStatement mappedStatement;
    private final Object parameterObject;
    private final BoundSql boundSql;
    
    @Override
    public void setParameters(PreparedStatement ps) {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();
                    JdbcType jdbcType = parameterMapping.getJdbcType();
                    if (value == null && jdbcType == null) {
                        jdbcType = configuration.getJdbcTypeForNull();
                    }
                    try {
                        typeHandler.setParameter(ps, i + 1, value, jdbcType);
                    } catch (TypeException | SQLException e) {
                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                    }
                }
            }
        }
    }
}

2.6 ResultSetHandler 结果映射

ResultSetHandler负责将JDBC ResultSet映射为Java对象。

java 复制代码
// ResultSetHandler接口
public interface ResultSetHandler {
    <E> List<E> handleResultSets(Statement stmt) throws SQLException;
    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
    void handleOutputParameters(CallableStatement cs) throws SQLException;
}

// DefaultResultSetHandler核心实现
public class DefaultResultSetHandler implements ResultSetHandler {
    private final Configuration configuration;
    private final MappedStatement mappedStatement;
    private final RowBounds rowBounds;
    private final ParameterHandler parameterHandler;
    private final ResultHandler<?> resultHandler;
    private final BoundSql boundSql;
    
    @Override
    public <E> List<E> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

        final List<Object> multipleResults = new ArrayList<>();

        int resultSetCount = 0;
        ResultSetWrapper rsw = getFirstResultSet(stmt);

        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
            ResultMap resultMap = resultMaps.get(resultSetCount);
            handleResultSet(rsw, resultMap, multipleResults, null);
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }

        String[] resultSets = mappedStatement.getResultSets();
        if (resultSets != null) {
            while (rsw != null && resultSetCount < resultSets.length) {
                ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
                if (parentMapping != null) {
                    String nestedResultMapId = parentMapping.getNestedResultMapId();
                    ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                    handleResultSet(rsw, resultMap, null, parentMapping);
                }
                rsw = getNextResultSet(stmt);
                cleanUpAfterHandlingResultSet();
                resultSetCount++;
            }
        }

        return collapseSingleResultList(multipleResults);
    }
}

三、Mapper接口代理机制深度解析

3.1 动态代理实现原理

MyBatis通过JDK动态代理实现Mapper接口的调用,主要涉及以下类:

  1. MapperProxyFactory:负责创建Mapper代理实例
  2. MapperProxy:实现InvocationHandler接口,处理方法调用
  3. MapperMethod:封装Mapper方法的相关信息

3.2 MapperMethod 完整实现

java 复制代码
public class MapperMethod {
    // 前面代码省略...
    
    private Object rowCountResult(int rowCount) {
        final Object result;
        if (method.returnsVoid()) {
            result = null;
        } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
            result = Integer.valueOf(rowCount);
        } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
            result = Long.valueOf(rowCount);
        } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
            result = Boolean.valueOf(rowCount > 0);
        } else {
            throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
        }
        return result;
    }
    
    private <E> void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
        MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
        if (!StatementType.CALLABLE.equals(ms.getStatementType()) && void.class.equals(ms.getResultMaps().get(0).getType())) {
            throw new BindingException("method " + command.getName() + " needs either a @ResultMap annotation, a @ResultType annotation, or a resultType attribute in XML to specify the result type.");
        }
        Object param = method.convertArgsToSqlCommandParam(args);
        if (method.hasRowBounds()) {
            RowBounds rowBounds = method.extractRowBounds(args);
            sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
        } else {
            sqlSession.select(command.getName(), param, method.extractResultHandler(args));
        }
    }
    
    private <E> List<E> executeForMany(SqlSession sqlSession, Object[] args) {
        List<E> result;
        Object param = method.convertArgsToSqlCommandParam(args);
        if (method.hasRowBounds()) {
            RowBounds rowBounds = method.extractRowBounds(args);
            result = sqlSession.selectList(command.getName(), param, rowBounds);
        } else {
            result = sqlSession.selectList(command.getName(), param);
        }
        // issue #510 Collections & arrays support
        if (!method.getReturnType().isAssignableFrom(result.getClass())) {
            if (method.getReturnType().isArray()) {
                result = convertToArray(result);
            } else {
                result = convertToDeclaredCollection(sqlSession.getConfiguration(), result);
            }
        }
        return result;
    }
}

四、缓存机制源码分析

4.1 一级缓存实现

一级缓存是SqlSession级别的缓存,默认开启。其实现主要在BaseExecutor中:

java 复制代码
public abstract class BaseExecutor implements Executor {
    protected PerpetualCache localCache;
    protected PerpetualCache localOutputParameterCache;
    
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameter);
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
    
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
            clearLocalCache();
        }
        List<E> list;
        try {
            queryStack++;
            // 先查询一级缓存
            list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
            if (list != null) {
                handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            } else {
                // 缓存未命中,执行查询
                list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
            }
        } finally {
            queryStack--;
        }
        if (queryStack == 0) {
            for (DeferredLoad deferredLoad : deferredLoads) {
                deferredLoad.load();
            }
            deferredLoads.clear(); // issue #601
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                clearLocalCache(); // issue #482
            }
        }
        return list;
    }
    
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        // 先向缓存中添加占位符
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
            // 调用子类的doQuery方法执行实际查询
            list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            // 查询完成后移除占位符
            localCache.removeObject(key);
        }
        // 将查询结果放入缓存
        localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            localOutputParameterCache.putObject(key, parameter);
        }
        return list;
    }
}

4.2 二级缓存实现

二级缓存是Mapper级别的缓存,通过装饰器模式实现:

java 复制代码
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) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
    
    @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); // issue #578 and #116
                }
                return list;
            }
        }
        // 没有配置二级缓存,直接委托给底层执行器查询
        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
    
    @Override
    public void commit(boolean required) throws SQLException {
        delegate.commit(required);
        // 提交时才真正写入二级缓存
        tcm.commit();
    }
}

五、插件机制源码分析

5.1 插件接口与执行流程

MyBatis的插件通过拦截器模式实现,允许开发者拦截四大核心组件的方法调用:

java 复制代码
// Interceptor接口
public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
    default Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    default void setProperties(Properties properties) {
        // NOP
    }
}

// Plugin类实现
public class Plugin implements InvocationHandler {
    private final Object target;
    private final Interceptor interceptor;
    private final Map<Class<?>, Set<Method>> signatureMap;
    
    private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
        this.target = target;
        this.interceptor = interceptor;
        this.signatureMap = signatureMap;
    }
    
    public static Object wrap(Object target, Interceptor interceptor) {
        Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
        Class<?> type = target.getClass();
        Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
        if (interfaces.length > 0) {
            return Proxy.newProxyInstance(
                type.getClassLoader(),
                interfaces,
                new Plugin(target, interceptor, signatureMap));
        }
        return target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            Set<Method> methods = signatureMap.get(method.getDeclaringClass());
            if (methods != null && methods.contains(method)) {
                // 拦截器方法执行
                return interceptor.intercept(new Invocation(target, method, args));
            }
            // 原方法执行
            return method.invoke(target, args);
        } catch (Exception e) {
            throw ExceptionUtil.unwrapThrowable(e);
        }
    }
}

六、动态SQL实现原理

6.1 动态SQL解析与处理

MyBatis的动态SQL通过以下组件实现:

java 复制代码
// DynamicContext 维护动态SQL构建过程中的上下文
public class DynamicContext {
    public static final String PARAMETER_OBJECT_KEY = "_parameter";
    public static final String DATABASE_ID_KEY = "_databaseId";
    
    private final ContextMap bindings;
    private final StringBuilder sqlBuilder = new StringBuilder();
    private int uniqueNumber = 0;
    
    // 其他方法...
    
    public void appendSql(String sql) {
        sqlBuilder.append(sql);
        sqlBuilder.append(" ");
    }
    
    public String getSql() {
        return sqlBuilder.toString().trim();
    }
}

// SqlNode 接口定义
public interface SqlNode {
    boolean apply(DynamicContext context);
}

// MixedSqlNode 组合多个SqlNode
public class MixedSqlNode implements SqlNode {
    private final List<SqlNode> contents;
    
    public MixedSqlNode(List<SqlNode> contents) {
        this.contents = contents;
    }
    
    @Override
    public boolean apply(DynamicContext context) {
        for (SqlNode sqlNode : contents) {
            sqlNode.apply(context);
        }
        return true;
    }
}

// TextSqlNode 处理文本节点
public class TextSqlNode implements SqlNode {
    private final String text;
    private final Pattern injectionFilter;
    
    // 其他方法...
    
    @Override
    public boolean apply(DynamicContext context) {
        GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
        context.appendSql(parser.parse(text));
        return true;
    }
}

6.2 动态SQL执行流程

动态SQL的执行过程:

  1. 解析XML配置或注解,生成SqlNode树
  2. 在执行SQL前,根据参数动态构建SQL语句
  3. 处理占位符和绑定参数
  4. 生成最终可执行的SQL

七、MyBatis初始化与配置解析

7.1 配置解析流程

java 复制代码
public class XmlConfigBuilder extends BaseBuilder {
    private boolean parsed;
    private final XPathParser parser;
    private String environment;
    private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
    
    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);
            loadCustomLogImpl(settings);
            typeAliasesElement(root.evalNode("typeAliases"));
            pluginElement(root.evalNode("plugins"));
            objectFactoryElement(root.evalNode("objectFactory"));
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            reflectorFactoryElement(root.evalNode("reflectorFactory"));
            settingsElement(settings);
            // read it after objectFactory and objectWrapperFactory issue #631
            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);
        }
    }
}

7.2 Mapper注册与解析

java 复制代码
private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
        for (XNode child : parent.getChildren()) {
            if ("package".equals(child.getName())) {
                String mapperPackage = child.getStringAttribute("name");
                configuration.addMappers(mapperPackage);
            } else {
                String resource = child.getStringAttribute("resource");
                String url = child.getStringAttribute("url");
                String mapperClass = child.getStringAttribute("class");
                if (resource != null && url == null && mapperClass == null) {
                    ErrorContext.instance().resource(resource);
                    InputStream inputStream = Resources.getResourceAsStream(resource);
                    XmlMapperBuilder mapperParser = new XmlMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
                    mapperParser.parse();
                } else if (resource == null && url != null && mapperClass == null) {
                    ErrorContext.instance().resource(url);
                    InputStream inputStream = Resources.getUrlAsStream(url);
                    XmlMapperBuilder mapperParser = new XmlMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
                    mapperParser.parse();
                } else if (resource == null && url == null && mapperClass != null) {
                    Class<?> mapperInterface = Resources.classForName(mapperClass);
                    configuration.addMapper(mapperInterface);
                } else {
                    throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                }
            }
        }
    }
}

八、MyBatis 与 Spring 集成原理

8.1 Spring 集成关键点

Spring与MyBatis的集成主要通过以下组件实现:

  1. SqlSessionFactoryBean:创建并配置SqlSessionFactory
  2. MapperScannerConfigurer:扫描Mapper接口并注册为Spring Bean
  3. SqlSessionTemplate:线程安全的SqlSession包装器
java 复制代码
// SqlSessionFactoryBean实现
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
    // 相关属性...
    
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化验证
        notNull(dataSource, "Property 'dataSource' is required");
        notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        
        // 创建SqlSessionFactory
        this.sqlSessionFactory = buildSqlSessionFactory();
    }
    
    @Override
    public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            afterPropertiesSet();
        }
        return this.sqlSessionFactory;
    }
}

// MapperScannerConfigurer实现
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    // 相关属性...
    
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            processPropertyPlaceHolders();
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.registerFilters();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }
}

九、MyBatis 高级特性源码解析

9.1 延迟加载机制

延迟加载通过代理模式实现,核心类为JavassistProxyFactory或CglibProxyFactory:

java 复制代码
// ProxyFactory接口
public interface ProxyFactory {
    Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
}

// JavassistProxyFactory实现
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);
    }
    
    public 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) {
                    // 处理Object类方法
                    if (WRITE_REPLACE_METHOD.equals(methodName)) {
                        Object original; 
                        if (constructorArgTypes.isEmpty()) {
                            original = objectFactory.create(type);
                        } else {
                            original = objectFactory.create(type, constructorArgTypes, constructorArgs);
                        }
                        PropertyCopier.copyBeanProperties(type, enhanced, original);
                        if (lazyLoader.size() > 0) {
                            return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
                        } else {
                            return original;
                        }
                    } else {
                        // 检查是否需要触发延迟加载
                        if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
                            if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
                                lazyLoader.loadAll();
                            } else if (PropertyNamer.isSetter(methodName)) {
                                final String property = PropertyNamer.methodToProperty(methodName);
                                lazyLoader.remove(property);
                            } else if (PropertyNamer.isGetter(methodName)) {
                                final String property = PropertyNamer.methodToProperty(methodName);
                                if (lazyLoader.hasLoader(property)) {
                                    lazyLoader.load(property);
                                }
                            }
                        }
                    }
                }
                // 调用原方法
                return methodProxy.invokeSuper(enhanced, args);
            } catch (Throwable t) {
                throw ExceptionUtil.unwrapThrowable(t);
            }
        }
    }
}

十、MyBatis 性能优化技巧

10.1 核心优化点

  1. SQL优化

    • 使用索引:确保WHERE条件中的列有适当的索引
    • 避免全表扫描:合理使用WHERE条件过滤数据
    • 减少子查询:考虑使用JOIN替代复杂子查询
  2. 映射优化

    • 使用resultMap:精确控制映射关系,避免不必要的列映射
    • 按需加载:使用延迟加载避免加载不必要的关联对象
    • 避免N+1问题:使用嵌套查询或连接查询优化关联加载
  3. 缓存优化

    • 合理配置二级缓存:根据业务场景决定是否启用
    • 设置适当的缓存范围:STATEMENT或SESSION级别
    • 自定义缓存实现:考虑使用Redis等分布式缓存
  4. 执行器选择

    • 批处理操作:使用BatchExecutor
    • 频繁重复SQL:使用ReuseExecutor
    • 一般场景:SimpleExecutor(默认)
  5. 连接池配置

    • 合理设置连接池大小
    • 配置适当的连接超时和最大生存时间

通过深入理解MyBatis的源码实现机制,开发者可以更好地掌握其工作原理,在实际项目中灵活应用各种特性,并针对具体场景进行性能优化,充分发挥MyBatis作为优秀持久层框架的优势。

相关推荐
lang201509282 小时前
Spring 4.1新特性:深度优化与生态整合
java·后端·spring
纳就这样吧2 小时前
Spring Cloud中@EnableDiscoveryClient注解详解
spring boot·后端·spring cloud
李慕婉学姐2 小时前
【开题答辩过程】以《重庆市社区养老服务小程序设计与实现》为例,不会开题答辩的可以进来看看
java·spring boot
DBLens数据库管理和开发工具2 小时前
GROUP BY隐性排序:MySQL 5.x 与 8.x 的行为大不同
后端
hello 早上好2 小时前
持久化输出与 ChatMemory
java·spring
oak隔壁找我2 小时前
Spring框架原理深度源码级解析
java·后端
回忆是昨天里的海2 小时前
k8s安装-kubeadm join,将工作节点加入k8s集群
java·服务器·kubernetes
yinke小琪2 小时前
谈谈项目中单点登录的实现原理
java·后端
浪飘3 小时前
k8s device plugin
java·docker·kubernetes