Reprinted from Javatalk–zhouhaocheng.com
MyBatis plug-in mechanism, the actual Java dynamic Proxy implementation of the responsibility chain model implementation.
According to the official document. MyBatis only allows you to intercept the following methods, this decision writes the Interceptor annotation signature parameter. 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:
/* 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 resultSetHa
Ndler = 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, MappedSta
Tement, 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 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
/@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:
/* Org.apache.ibatis.plugin.Plugin class/public class plugin implements Invocationhandler {/* ellipsis code .../public Stati C Object Wrap (object target, Interceptor Interceptor) {/* Here is to obtain the Interceptor annotation signature/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 (), interface
S, 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 Thr
owable {try {set<method> methods = Signaturemap.get (Method.getdeclaringclass ()); if (Methods!= null && Methods.contains (method)) {/* Execute Interceptor Methods */Return Interceptor.intercept (new INvocation (target, method, args));
Return Method.invoke (target, args);
catch (Exception e) {throw exceptionutil.unwrapthrowable (e); }/* Omit code ... * *