MyBatis provides plug-in mechanism, so that we can enhance the function of MyBatis according to our own needs. Thus, the behavior of the four core objects can be changed without modifying the original code. This article will analyze how the plug-in works from a source point of view.
Source code address:
Mybatis Chinese annotation source code
Example of mybatis usage
Which objects and methods can be intercepted
MyBatis allows you to intercept calls at some point during the execution of a mapping statement. By default, MyBatis allows you to intercept method calls using plug-ins:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
Let’s take Executor as an example.
Executor weaves into the interceptor
The Executor interceptor is woven into openSession(). Specifically, creatingExecutor
Weave in.
From the source can be seen, create finishedExecutor
After that, it callsInterceptorChain
thepluginAll()
Method is woven into the interceptor.
InterceptorChain
Object is a collection of all plug-ins,pluginAll()
It’s just iterating through the plug-in and executing the plug-inplguin()
Methods. The plug-in interface is defined as follows:
Among themplugin()
The implementation of the method is generallyPlugin.wrap()
:
Continue to look atPlugin.wrap()
Source code implementation:
Wrap (), via the JDK proxy, returns a proxy object whose InvocationHandler is the Plugin object. Thus, the invoke() method of the Plugin ends up executing when executed. We’ll look at that later.
If no interface is matched, no proxy is performed
Interceptors are woven into StatementHandler, parameterHandler, and resultSetHandler objects in the same way that executors do, after the object is created, Call the pluginAll() method that calls the InterceptorChain to weave into the interceptor. Don’t go into
Plug-in call flow
We know that callingMapper
Interface methods are executed eventuallyExecutor
theupdate()
orquery()
Methods. And in the case of plug-ins,Executor
Is a proxy object and is therefore called firstPlugin
theinvoke()
Methods:
Invocation
The definition is as follows:
The Proceed () method is called after the Invocation of the plug-in logic.
It can be seen from the source code, Mybatis plug-in is through layers of packaging to achieve interceptor chain call. Given that we have two Executor plug-ins, the invoke() method of the Plugin is first called when we call Executor’s Query (). The Taget is still a proxy object, so invocation of the invocation.Proceed () method at the end of the first plug-in invocation calls Plugin’s invoke() method again into the next plug-in’s logic, and the target is the actual Executor object. The original method implementation is finally called to perform subsequent operations.
This is different from Spring’s AOP implementation, which wraps only one layer and loops through all the woven logic in that layer’s proxy on invocation. Finally, the original method is executed.
Original is not easy, feel that the article is written well small partners, a praise 👍 to encourage it ~
Welcome to my open source project: a lightweight HTTP invocation framework for SpringBoot