Einführung in MyBatis Interceptor
MyBatis bietet eine Plugin -Funktion. Obwohl es als Plugin bezeichnet wird, handelt es sich tatsächlich um eine Interceptor -Funktion. Was fängt der Interceptor MyBatis ab?
Gehen wir zur offiziellen Website, um einen Blick darauf zu werfen:
Mit MyBatis können Sie Anrufe während der Ausführung einer zugeordneten Anweisung an einem bestimmten Punkt abfangen. Standardmäßig ermöglicht Methodenaufrufe MyBatis ermöglicht Plugins, abzufangen, einschließlich:
Wir haben einige Methoden gesehen, die die Ausführungsschnittstelle abfangen können, z. B. Aktualisierung, Abfrage, Commit, Rollback und andere Methoden sowie einige Methoden anderer Schnittstellen
Warten.
Die Gesamtübersicht lautet:
Verwendung von Interceptors
Interceptor -Einführung und Konfiguration
Schauen wir uns zunächst die Schnittstellendefinition des MyBatis Interceptor an:
öffentliche Schnittstelle Interceptor {Object Intercept (Invocation Invocation) löst Throwable; Objekt -Plugin (Objektziel); void setProperties (Eigenschaften Eigenschaften);}Es ist relativ einfach, es gibt nur 3 Methoden. MyBatis hat standardmäßig keine Interceptor Interface -Implementierungsklasse, und Entwickler können Interceptors implementieren, die ihren Anforderungen entsprechen.
Hier ist ein Beispiel für einen Interceptor von der offiziellen Website von MyBatis:
@Intercepts ({@Signature (type = executor.class, method = "update", args = {mapPedStatement.class, Object.class})}) public class Beispielplugin implementiert Interceptor {public Object Intercept (Invocation Invocation) wirft Throwable {return Invocation.prosector (); } öffentliches Objekt -Plugin (Objektziel) {return plugin.wrap (target, this); } public void setProperties (Eigenschaften Eigenschaften) {}}Globale XML -Konfiguration:
<plugins> <plugin interceptor = "org.format.mybatis.cache.Interceptor.exampleplugin"> </plugin> </plugins>
Dieser Interceptor fängt die Aktualisierungsmethode der Executor -Schnittstelle ab (tatsächlich handelt es sich um Hinzufügung, Löschung und Modifikationsvorgänge von SQLSession). Alle Update -Methoden, die Executor -Executor ausführen, werden vom Interceptor abgefangen.
Quellcodeanalyse
Lassen Sie uns den Quellcode hinter diesem Code analysieren.
Starten Sie zunächst die Analyse aus der Quell-> Konfigurationsdatei:
XMLConfigBuilder Parses Pluginelement Private Methode der myBatis Global Configuration -Datei:
private void pluginelement (xnode übergeordnet) löst Ausnahme aus {if (parent! = null) {für (xnode child: parent.getChildren ()) {String interceptor = child.getStringattribute ("interceptor"); Properties Properties = Child.getChildrenaSProperties (); Interceptor InterceptorinStance = (Interceptor) ResolVeclass (Interceptor) .NewInstance (); interceptorinstance.setProperties (Eigenschaften); configuration.addInterceptor (InterceptorinStance); }}}Der spezifische Parsingcode ist eigentlich relativ einfach, daher werde ich ihn nicht veröffentlichen. Es instanziiert hauptsächlich die Klasse, die durch das Interceptor -Attribut im Pluginknoten durch Reflexion dargestellt wird. Rufen Sie dann die AddInterceptor -Methode der globalen Konfigurationsklassenkonfiguration auf.
public void addInterceptor (interceptor interceptor) {interceptorChain.addInterceptor (Interceptor); }Diese InterceptorChain ist eine interne Eigenschaft der Konfiguration, und ihr Typ ist InterceptorChain, eine Interceptor -Kette. Schauen wir uns die Definition an:
öffentliche Klasse InterceptorChain {private endgültige Liste <interceptor> interceptors = new ArrayList <Cinceptor> (); öffentliches Objekt -Pluginall (Objektziel) {für (Interceptor interceptor: interceptors) {target = interceptor.plugin (Ziel); } return target; } public void addInterceptor (interceptor interceptor) {interceptors.add (interceptor); } public list <Cinceptor> getInterceptors () {return collections.unmodifiablelist (interceptors); }}Nachdem wir die Analyse der Interceptor -Konfiguration und das Eigentum des Interceptors verstehen, blicken wir nun zurück, warum der Interceptor diese Methoden (Teilmethoden des Executors, ParameterHandler, ResultsStHander) abfangen:
public ParameterHandler NewParameterHandler (MapChedStatement MapChdStatement, Object ParameterObject, boundSQL boundsql) {parameterHandler parameterHandler = mappedStatement.getlang (). CreateParameterHandler (Maptstatement, ParameterObject, bodenSQL); parameterHandler = (parameterHandler) interceptorChain.pluginall (ParameterHandler); return parameterHandler;}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 = (resultSthandler) interceptorChain.pluginall (resultsHandhandler); 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, bodensql); StatementHandler = (StatementHandler) interceptorChain.pluginall (StatementHandler); return titiesHandler;} public Executor Neexecutor (Transaktionstransaktion, Executortype Executortype, Boolean AutoCommit) {Executortype = Executortype == NULL? DefaultExecUTortype: ExecUTortype; EXTROTORTYP = EXTROTORTYP == NULL? ExecUTOrtype.Simple: Executortype; Testamentsvollstrecker; if (outortype.batch == Executortype) {executor = new batchexecutor (this, Transaktion); } else if (operortype.REUSE == ExecUtOrtype) {executor = new Reusexexecutor (this, Transaktion); } else {executor = new SimpleExecutor (this, Transaction); } if (cacheeNabled) {executor = new CachingExecutor (Executor, AutoCommit); } Executor = (Executor) interceptorChain.pluginall (Executor); Ausführender zurückgeben;}Die obigen 4 Methoden sind alle Konfigurationsmethoden. Diese Methoden werden in einem Betrieb von MyBatis ausgeführt (hinzufügen, löschen, ändern und abfragen). Die Reihenfolge der Ausführung ist Executor, ParameterHandler, resultStHandler, Erklärung (wo ParameterHandler und ResultensStracherdler erstellt werden, wenn Erstellungshandler erstellt wird [3 verfügbare Implementierungsklassen CallablestatementHandler, PrepedStatementHandler, SimpleStatementHandler], und der Konstruktor nennt den Konstruktor [die Konstrukteure dieser drei Implementierungsklassen ".
Nachdem diese 4 Methoden das entsprechende Objekt instanziieren, rufen sie die Pluginall -Methode von InterceptorChain auf. Wie bereits erwähnt, wurde das Pluginall von InterceptorChain eingeführt, das alle Interceptors durchqueren und dann die Plugin -Methode jedes Interceptors aufruft. Hinweis: Der Rückgabewert der Plugin -Methode des Interceptor wird dem ursprünglichen Objekt direkt zugeordnet.
Da StatementHandler abgefangen werden kann, befasst sich diese Schnittstelle hauptsächlich mit der Konstruktion der SQL -Syntax. Daher kann beispielsweise die Funktion von Paging mit einem Interceptor implementiert werden. Sie müssen die SQL nur in der Implementierungsklasse für AnweisungSpanceLer -Schnittstellen in der Plugin -Methode des Interceptor verarbeiten, und Sie können die Reflexion verwenden, um sie zu implementieren.
MyBatis bietet auch Annotationen für @Intercepts und @signature über Interceptors. Das Beispiel der offiziellen Website ist die Verwendung dieser beiden Anmerkungen, einschließlich der Verwendung der Plugin -Klasse:
@Overridepublic Object Plugin (Objektziel) {return plugin.wrap (target, this);}Lassen Sie uns die Quellcodes dieser 3 "neuen Kombinationen" analysieren. Schauen wir uns zunächst die Wrap -Methode der Plugin -Klasse an:
public static Object Wrap (Objektziel, Interceptor Interceptor) {map <class <?>, Set <Methode >> Signaturemap = GetSignaturemap (Interceptor); Klasse <?> Type = target.getClass (); Klasse <?> [] Interfaces = getAllinterfaces (Typ, Signaturemap); if (interfaces.length> 0) {return proxy.newproxyinstance (type.getClassloader (), Schnittstellen, neues Plugin (Ziel, Schnittstelle, Signaturemap)); } return target;}Die Plugin -Klasse implementiert die InvocationHandler -Schnittstelle. Offensichtlich sehen wir, dass eine dynamische Proxyklasse, die vom JDK selbst bereitgestellt wird, hierher zurückgegeben wird. Lassen Sie uns andere Methoden analysieren, die nach dieser Methode aufgerufen werden:
Getsignaturemap -Methode:
private static map <class <?>, set <methode >> GetSignaturemap (Interceptor Interceptor) {Intercepts interceptsannotation = interceptor.getClass (). getAnnotation (intercepts.class); if (interceptsAnnotation == null) {// Ausgabe #251 Neue Pluginexception werfen ("no @Intercepts Annotation wurde in Interceptor gefunden" + interceptor.getClass (). getName ()); } Signature [] Sigs = interceptsannotation.Value (); Map <class <?>, Set <methode >> Signaturemap = new HashMap <class <?>, Set <methode >> (); für (Signature sig: sigs) {set <Methoden> methodes = Signaturemap.get (sig.type ()); if (methoden == null) {methody = new Hashset <Methode> (); Signaturemap.put (Sig.Type (), Methoden); } try {method method = sig.type (). getMethod (sig.method (), sig.args ()); methods.Add (Methode); } catch (NoSuchMethodException e) {Neue Pluginexception werfen ("konnte keine Methode auf" + sig.type () + "namens" + sig.method () + ". Ursache:" + e, e); }} return Signaturemap;}Die Erläuterung der Getsignaturemap -Methode: Erstens erhalten Sie die @Interceptors -Annotation der Interceptor -Klasse, dann die @signature Annotation Sammlung von Attributen dieser Annotation und durchqueren Sie diese Sammlung, nehmen Sie das Typ -Attribut (Klassentyp) der @Signature -Annotation heraus und erhalten Sie die Methode mit der Methode Attribut und Args -Attribut basierend auf diesem Typ. Da das von @Interceptors kommentierte Attribut @Signature eine Eigenschaft ist, gibt es schließlich eine Karte mit Typ als Schlüssel und Wert als SET <Methode> zurück.
@Intercepts ({@Signature (type = executor.class, method = "update", args = {mapPedStatement.class, Object.class})})Beispielsweise gibt die @Interceptors -Annotation einen Schlüssel als Ausführungskraft und Wert als Sammlung zurück (in dieser Sammlung gibt es nur ein Element, dh die Methodeinstanz ist diese Methode -Instanz die Update -Methode der Ausführungsschnittstelle und diese Methode hat Parameter von Typenkapitionen und Objekt). Diese Methodeinstanz wird basierend auf der Methode und den Argsattributen von @signature erhalten. Wenn der Args -Parameter nicht der Methode des Typs vom Typ Typ entspricht, wird eine Ausnahme ausgelöst.
GetAllinterfaces -Methode:
private statische Klasse <?> [] GetAllinterfaces (Klasse <?> Typ, Karte <Klasse <?>, Set <Methode >> Signaturemap) {set <class <? >> interfaces = new Hashset <Klasse <>> (); while (type! }} type = type.getSuperClass (); } return interfaces.toArray (neue Klasse <?> [interfaces.size ()]);}Die GetAllinterfaces -Methode Erläuterung: Gemäß dem Zielinstanzziel (dieses Ziel ist die Klasse, die der MyBatis -Interceptor wie zuvor erwähnt, ausführender, ausführender, ParameterHandler, resultSthandler, StatementHandler) und seine übergeordneten Klassen des Interface -Arrays in der Signaturemap zurückgeben kann.
Daher besteht die Funktion der Plugin -Klasse darin, das Attribut @Signature -Array der kommentierten Attribute basierend auf der Annotation @Interceptors zu erhalten und dann die entsprechende Methode gemäß den Annotierungen für Typ-, Methoden und Args zu verwenden. Basierend auf der vom aufgerufenen Zielobjekt implementierten Schnittstelle entscheiden Sie schließlich, ob ein Proxy -Objekt zurückgegeben werden soll, um das ursprüngliche Zielobjekt zu ersetzen.
Auf der offiziellen Website von MyBatis Official wird beispielsweise die Methode der Chefutor -Interface vom Interceptor abgefangen. Das Ende wird also mit einem Proxy -Klassen -Plugin zurückgegeben, nicht mit einem Testamentsvollstrecker. Wenn Sie die Methode auf diese Weise aufrufen, wird es ausgeführt, wenn es sich um eine Proxy -Klasse handelt:
öffentliches Objekt invoke (Object Proxy, Method -Methode, Object [] args) löscht Throwable {try {set <Methode> methody = Signaturemap.get (method.getDeclaringClass ()) aus; if (Methoden! = null && methods.contains (methode)) {return interceptor.Intercept (neuer Aufruf (Ziel, Methode, Argumentation)); } return methode.invoke (Ziel, args); } catch (Exception E) {throutsUtutil.unwrapthrowable (e); }}Das ist richtig, wenn die entsprechende Methode gefunden und proxyiert ist, wird die Interceptor -Methode der Interceptor -Schnittstelle ausgeführt.
Diese Aufrufklasse lautet wie folgt:
öffentlicher Klassenaufruf {private Objektziel; private Methode; privates Objekt [] args; public Invocation (Objektziel, Methodenmethode, Objekt [] args) {this.target = target; this.method = Methode; this.args = args; } public Object GetTarget () {return target; } public method getMethod () {return -Methode; } public Object [] getargs () {return args; } public Object protous () löst invocationTargetException, illegalAccessException {return methode.invoke (Ziel, args); }}Seine Prozessmethode besteht darin, die ursprüngliche Methode (kein Proxy) aufzurufen.
Zusammenfassen
Unter den drei Methoden der MyBatis -Interceptor -Schnittstelle wird die Plugin -Methode im Konstruktionsprozess bestimmter Prozessoren (Handler) verwendet. Die Interceptor -Methode wird verwendet, um die Ausführung der Proxy -Klasse zu verarbeiten. Die SetProperties -Methode wird verwendet, um die Interceptor -Eigenschaften festzulegen.
Tatsächlich werden die von der myBatis offiziellen Website bereitgestellten Methoden @Interceptors und @signature Anmerkungen und Pluginklassen zur Verarbeitung von Interceptors nicht unbedingt direkt verwendet. Wir können diese drei Klassen auch aufgeben und entsprechende Vorgänge basierend auf dem Typ der Zielinstanz innerhalb der Plugin -Methode direkt ausführen.
Insgesamt ist der MyBatis -Interceptor immer noch sehr einfach. Der Interceptor selbst erfordert nicht zu viele Wissenspunkte, aber das Lernen des Interceptors erfordert Vertrautheit mit jeder Schnittstelle in MyBatis, da der Interceptor die Wissenspunkte jeder Schnittstelle beinhaltet.
Zusammenfassen
Das obige ist eine Erforschung der Prinzipien von MyBatis Interceptor, die vom Herausgeber eingeführt wurden. Ich hoffe, es wird für alle hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird allen rechtzeitig antworten. Vielen Dank für Ihre Unterstützung auf der Wulin.com -Website!