Unlock MyBatis Plugin Mechanics: Build Custom Interceptors and Pagination

This article explains MyBatis's plugin architecture, shows how to create a custom interceptor to modify query parameters, demonstrates injection into Spring Boot, and analyzes the underlying proxy generation and execution flow, including a brief look at the popular PageHelper pagination plugin.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Unlock MyBatis Plugin Mechanics: Build Custom Interceptors and Pagination

Introduction

MyBatis pagination plugins are widely used; this article explains the underlying plugin mechanism and how to build custom interceptors.

Environment Setup

All examples assume MyBatis 3.5 and Spring Boot 2.3.3.RELEASE.

What Is a Plugin?

Plugins in MyBatis allow interception of specific component methods. The four core components are Executor, ParameterHandler, ResultSetHandler, and StatementHandler, each exposing several methods that can be intercepted.

Creating a Custom Plugin

Implement the Interceptor interface and override intercept, plugin, and setProperties. Example code:

public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
    Object plugin(Object target);
    void setProperties(Properties properties);
}

Example: Modify Query Parameter

Goal: change the parameter of selectByUserId to a fixed value. The appropriate interception point is ParameterHandler.setParameters(). The custom interceptor uses @Intercepts and @Signature annotations to target this method.

@Intercepts({
    @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
public class ParameterInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("Interceptor executing:" + invocation.getTarget());
        Object target = invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(target);
        String value = (String) metaObject.getValue("mappedStatement.id");
        if ("cn.cb.demo.dao.UserMapper.selectByUserId".equals(value)) {
            metaObject.setValue("parameterObject", "admin_1");
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) { }
}

Required Annotations

@Intercepts

: marks the class as a MyBatis interceptor. @Signature: defines the target type, method name, and argument types for interception.

Injecting the Plugin into Spring Boot

Define a configuration class that declares an Interceptor[] bean containing the custom interceptor. Spring Boot’s MyBatis auto‑configuration picks up this bean and adds it to the interceptor chain.

@Configuration
public class MybatisConfig {
    @Bean
    public Interceptor[] interceptors() {
        ParameterInterceptor parameterInterceptor = new ParameterInterceptor();
        return new Interceptor[]{parameterInterceptor};
    }
}

Testing the Plugin

Running a test that calls selectByUserId("1222") will return the user with id admin_1 because the interceptor rewrites the parameter.

Plugin Mechanism Deep Dive

During MyBatis initialization, each core component is created via methods in Configuration. After creation, interceptorChain.pluginAll(component) wraps the component with a dynamic proxy ( Plugin).

Generating the Proxy

The pluginAll() method iterates over all registered interceptors and calls interceptor.plugin(target). Plugin.wrap() builds a JDK proxy that implements the interfaces declared in the interceptor’s @Signature definitions.

Invocation Process

The proxy’s invoke() method checks whether the invoked method matches any signature. If it does, the interceptor’s intercept() method runs; otherwise, the original method is invoked.

Execution Flow Example

When PreparedStatementHandler.setParameters() is called, the proxy intercepts the call.

The interceptor modifies the parameter object and then proceeds with the original execution.

Summary of Plugin Steps

At startup, MyBatis determines which components are intercepted.

Intercepted components are wrapped in a Plugin proxy.

Method calls on a proxied component trigger the proxy’s invoke().

If the method matches a signature, the interceptor’s intercept() runs; otherwise, the original method executes.

Pagination Plugin Analysis

The widely used pagehelper library (Maven coordinates com.github.pagehelper:pagehelper:5.1.6) implements pagination by defining a PageInterceptor that intercepts Executor.query() methods and rewrites RowBounds based on the requested page.

@Intercepts({
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class PageInterceptor implements Interceptor { }

The interceptor adjusts the SQL and parameters to achieve pagination; detailed dialect handling is omitted for brevity.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavapluginMyBatispaginationInterceptorSpringBoot
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.