There are a lot of Java beginners for the MyBatis interceptor Inteceptor is not very understanding, here I will organize the next chapter on the Java MyBatis Interceptor Inteceptor detailed,
This paper mainly analyzes the plug-in mechanism of mybatis, in fact, is the implementation of the responsibility chain model of Java dynamic Proxy implementation.
According to the official document. MyBatis only allows you to intercept the following methods, this decision writes the Interceptor annotation signature parameter.
The code is as follows
Executor (update, query, Flushstatements, Commit, rollback, gettransaction, close, isclosed)
Parameterhandler ( Getparameterobject, Setparameters)
Resultsethandler (handleresultsets, handleoutputparameters)
Statementhandler (Prepare, parameterize, batch, update, query)
Interception processing of the source code is as follows, which Interceptorchain.pluginall (..) That is, to weave the custom interceptor:
The code is as follows
/* Org.apache.ibatis.session.Configuration class method */Public Parameterhandler Newparameterhandler (mappedstatement Mappedstatement, Object parameterobject, Boundsql boundsql) {Parameterhandler Parameterhandler = MappedStatement.getLa
Ng (). Createparameterhandler (Mappedstatement, Parameterobject, Boundsql);
/* Intercept parameterhandler*/Parameterhandler = (parameterhandler) interceptorchain.pluginall (ParameterHandler);
return parameterhandler; Public Resultsethandler Newresultsethandler (Executor Executor, mappedstatement mappedstatement, Rowbounds rowbounds, Parameterhandler Parameterhandler, Resulthandler Resulthandler, Boundsql boundsql) {Resultsethandler ResultSetHandle
R = new Defaultresultsethandler (executor, mappedstatement, Parameterhandler, Resulthandler, Boundsql, rowBounds);
/* Intercept resultsethandler*/Resultsethandler = (resultsethandler) interceptorchain.pluginall (ResultSetHandler);
return resultsethandler; } 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);
/* Intercept statementhandler*/Statementhandler = (statementhandler) interceptorchain.pluginall (StatementHandler);
return statementhandler; } 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);
} /* Intercept executor*/executor = (executor) interceptorchain.pluginall (executor);
return executor;
}
Implementation of a custom interceptor only need to implement the Interceptor interface, the approximate code is as follows:
The code is as follows
/* The annotation indicates which interface is to be intercepted and its parameters
/@Intercepts ({@Signature (type = Statementhandler.class, method = "Prepare", args = {Connecti On.class})}) Public
class Yourinterceptor implements interceptor{public
Object Intercept (invocation Invocation) throws throwable{
dosomething ();
/* Note: This is actually done using the Invocation.proceed () method to complete the traversal call of the Interceptorchain chain (that is, execute all registered Interceptor intercept methods) to the end of the proxy object's original method call. return
invocation.proceed ();
}
/* Generates proxies for target targets, and @intercepts annotations are used in plugin.wrap for the *
/@Override Public
Object Plugin (object target) {
/* When the target class is a statementhandler type, just wrap the target class, do not make meaningless agent
/return (target instanceof Statementhandler)? Plugin.wrap (target, this): target;
}
/* Used to set custom interceptor configuration parameters *
/@Override public
void SetProperties (Properties properties) {
}
}
Where the code that intercepts the call is in Plugin.wrap:
The code is as follows
/* Org.apache.ibatis.plugin.Plugin class/public class plugin implements Invocationhandler {/* ellipsis code ... */public static O Bject Wrap (Object target, Interceptor Interceptor) {//* Here is the note signing for Interceptor/Map<class<?>, Set<method
>> Signaturemap = Getsignaturemap (Interceptor);
class<?> type = Target.getclass ();
/* Get intercept target class match interface * * class<?>[] interfaces = getallinterfaces (type, signaturemap); if (Interfaces.length > 0) {/* Use JDK Dynamic proxy/return Proxy.newproxyinstance (Type.getclassloader (), interfaces, new
Plugin (target, Interceptor, Signaturemap));
return target; }/* The execution of all methods of intercepting the target class will change to execute here/@Override public object Invoke (Object proxy, methods method, object[] args) throws Throwab
Le {try {set<method> methods = Signaturemap.get (Method.getdeclaringclass ()); if (Methods!= null && Methods.contains (method)) {/* Execute Interceptor Methods */Return interceptor.intercept (new Invocati
On (target, method, args)); } RetuRN Method.invoke (target, args);
catch (Exception e) {throw exceptionutil.unwrapthrowable (e);
}/* Omit code ... * *
You can see that MyBatis's Interceptor design core code is relatively simple, but flexible enough. Notice when actually used, do not make meaningless proxies (plugin.wrap).