MyBatis-Plugins 的创建流程与执行顺序(源码)

本文详细解析了MyBatis的插件机制,包括插件如何被添加到InterceptorChain类中,四大对象(Executor、ParameterHandler、ResultSetHandler、StatementHandler)的创建顺序及插件处理流程,以及不同和相同类型插件的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、插件的解析,所有插件都会被添加到 InterceptorChain 类中,用于后续处理

org.apache.ibatis.builder.xml.XMLConfigBuilder

private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
        for (XNode child : parent.getChildren()) {
            String interceptor = child.getStringAttribute("interceptor");
            Properties properties = child.getChildrenAsProperties();
            Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
            interceptorInstance.setProperties(properties);
            configuration.addInterceptor(interceptorInstance);
        }
    }
}

org.apache.ibatis.session.Configuration

public void addInterceptor(Interceptor interceptor) {
    interceptorChain.addInterceptor(interceptor);
}

 

二、四大对象的创建顺序,都会经过 interceptorChain.pluginAll() 进行处理

1.Executor,SQL语句执行器

org.apache.ibatis.session.Configuration

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : 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);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

 

2.ParameterHandler,参数处理器

org.apache.ibatis.executor.statement.BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
        generateKeys(parameterObject);
        boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

org.apache.ibatis.session.Configuration

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
}

 

3.ResultSetHandler,结果集处理器

org.apache.ibatis.executor.statement.BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
        generateKeys(parameterObject);
        boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

org.apache.ibatis.session.Configuration

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
}

 

4.StatementHandler,SQL语句处理器

org.apache.ibatis.executor.SimpleExecutor

@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.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

org.apache.ibatis.session.Configuration

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}

 

三、多个不同类型插件的执行顺序

org.apache.ibatis.executor.SimpleExecutor

@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());
        // 3.执行 SQL 语句,封装结果集,ResultSetHandler 拦截插件执行
        return handler.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    // 1.准备语句,StatementHandler 拦截插件执行
    stmt = handler.prepare(connection, transaction.getTimeout());
    // 2.SQL 语句参数处理,ParameterHandler 拦截插件执行
    handler.parameterize(stmt);
    return stmt;
}

 

四、多个相同类型插件的执行顺序,以  StatementHandler 为例

1.创建顺序,按照配置顺序层层代理,最后配置的插件为最外层代理

配置了两个插件

<plugins>
    <plugin interceptor="com.plugins.ExamplePlugin"></plugin>
    <plugin interceptor="com.plugins.ExamplePlugin2"></plugin>
</plugins>

1.1.准备创建

1.2.最开始要执行的对象

1.3.开始创建

1.4.创建完毕

2.执行顺序,按照配置顺序倒序执行

2.1.第一次执行,ExamplePlugin2

2.2.第二次执行,ExamplePlugin

2.3.最终执行

3.示意图

转载于:https://www.cnblogs.com/jhxxb/p/10692496.html

*************************** APPLICATION FAILED TO START *************************** Description: An attempt was made to call a method that does not exist. The attempt was made from the following location: com.baomidou.mybatisplus.core.MybatisXMLScriptBuilder$ForEachHandler.handleNode(MybatisXMLScriptBuilder.java:230) The following method did not exist: 'void org.apache.ibatis.scripting.xmltags.ForEachSqlNode.<init>(org.apache.ibatis.session.Configuration, org.apache.ibatis.scripting.xmltags.SqlNode, java.lang.String, java.lang.Boolean, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)' The calling method's class, com.baomidou.mybatisplus.core.MybatisXMLScriptBuilder$ForEachHandler, was loaded from the following location: jar:file:/C:/Users/z'q'z/.m2/repository/com/baomidou/mybatis-plus-core/3.5.7/mybatis-plus-core-3.5.7.jar!/com/baomidou/mybatisplus/core/MybatisXMLScriptBuilder$ForEachHandler.class The called method's class, org.apache.ibatis.scripting.xmltags.ForEachSqlNode, is available from the following locations: jar:file:/C:/Users/z'q'z/.m2/repository/org/mybatis/mybatis/3.5.5/mybatis-3.5.5.jar!/org/apache/ibatis/scripting/xmltags/ForEachSqlNode.class The called method's class hierarchy was loaded from the following locations: org.apache.ibatis.scripting.xmltags.ForEachSqlNode: file:/C:/Users/z'q'z/.m2/repository/org/mybatis/mybatis/3.5.5/mybatis-3.5.5.jar Action: Correct the classpath of your application so that it contains compatible versions of the classes com.baomidou.mybatisplus.core.MybatisXMLScriptBuilder$ForEachHandler and org.apache.ibatis.scripting.xmltags.ForEachSqlNode
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值