Pengantar Mybatis Interceptor
MyBatis menyediakan fungsi plugin. Meskipun disebut plugin, itu sebenarnya adalah fungsi pencegat. Jadi apa yang dicegat Mybatis?
Mari kita pergi ke situs web resmi untuk melihatnya:
Mybatis memungkinkan Anda untuk mencegat panggilan pada titik tertentu selama pelaksanaan pernyataan yang dipetakan. Secara default, metode panggilan mybatis memungkinkan plugin untuk mencegat termasuk:
Kami telah melihat beberapa metode yang dapat mencegat antarmuka pelaksana, seperti pembaruan, kueri, komit, rollback dan metode lainnya, serta beberapa metode antarmuka lainnya
Tunggu.
Ringkasan keseluruhannya adalah:
Penggunaan Pencegat
Pendahuluan dan Konfigurasi Interceptor
Pertama, mari kita lihat definisi antarmuka Mybatis Interceptor:
Public Interface Interceptor {Object Intercept (Invocation Invocation) melempar Throwable; Plugin objek (target objek); void setProperties (properti properti);}Ini relatif sederhana, hanya ada 3 metode. Mybatis tidak memiliki kelas implementasi antarmuka interceptor secara default, dan pengembang dapat menerapkan pencegat yang memenuhi kebutuhan mereka.
Berikut adalah contoh pencegat dari situs web resmi Mybatis:
@Intercepts ({@Signature (type = executor.class, Method = "update", args = {mappedstatement.class, objek.class})}) kelas publik Contoh splugin mengimplementasikan interceptor {intersep objek publik (doa invokasi) melempar lemparan {return doa return.proCed (); } plugin objek publik (target objek) {return plugin.wrap (target, this); } public void setProperties (properti properti) {}}Konfigurasi XML Global:
<Plugin> <plugin interceptor = "org.format.mybatis.cache.interceptor.examplePlugin"> </plugin> </plugins>
Interceptor ini mencegat metode pembaruan antarmuka eksekutor (pada kenyataannya, ini adalah penambahan, penghapusan, dan operasi modifikasi SQLSESSION). Semua metode pembaruan yang dieksekusi oleh pelaksana akan dicegat oleh Interceptor.
Analisis Kode Sumber
Mari kita analisis kode sumber di balik kode ini.
Pertama, mulailah analisis dari sumber-> file konfigurasi:
XMLConfigBuilder Metode Privat PluginElement Private Mybatis Global Configuration File:
private void plugineLement (Xnode Parent) melempar Exception {if (Parent! = null) {for (xnode child: parent.getChildren ()) {string interceptor = child.getStringAttribute ("interceptor"); Properties Properties = Child.getChildrenasProperties (); Interceptor interceptorinstance = (interceptor) resolveclass (interceptor) .newinstance (); interceptorinstance.setProperties (properti); configuration.addInterceptor (interceptorInstance); }}}Kode parsing spesifik sebenarnya relatif sederhana, jadi saya tidak akan mempostingnya. Ini terutama membuat kelas yang diwakili oleh atribut interceptor di node plugin dengan refleksi. Kemudian hubungi metode addInterceptor dari konfigurasi kelas konfigurasi global.
public void addInterceptor (Interceptor Interceptor) {InterceptorChain.AddInterceptor (Interceptor); }Interceptorchain ini adalah properti internal konfigurasi, dan jenisnya adalah InterceptorChain, yang merupakan rantai interseptor. Mari kita lihat definisinya:
Public Class InterceptorChain {Private Final List <Perpeseptor> Interceptors = New ArrayList <PerpesepTor> (); pluginall objek publik (objek target) {for (interceptor interceptor: interceptor) {target = interceptor.plugin (target); } return target; } public void addInterceptor (Interceptor Interceptor) {Interceptor.Add (Interceptor); } Daftar Publik <Enterceptor> getInterceptors () {return collections.unmodifiblelist (interceptors); }}Sekarang kami memahami penguraian konfigurasi interceptor dan kepemilikan pencegat, kami sekarang melihat kembali mengapa interseptor mencegat metode ini (metode parsial pelaksana, parameterhandler, resultSethandler):
Parameterhandler publik NewParameterHandler (MappedStatement MappedStatement, Object ParameterObject, BoundSQL BoundSQL) {ParameterHandler ParameterHandler = MappedStatement.getlang (). CreateParamEthandler (MappedStatement, ParameterObject, BoundSQL); 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); HasilSethandler = (hasilSethandler) interceptorchain.pluginall (hasilSethandler); 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); pernyataanhandler = (pernyataanhandler) interceptorchain.pluginall (pernyataanhandler); Return Pernyataan Handler;} Eksekutor Publik NewExecutor (Transaction Transaction, ExecutorType ExecutorType, Boolean AutoCommit) {ExecutorType = ExecutorType == NULL? DefaultExecutorType: ExecutorType; ExecutorType = ExecutorType == NULL? Executortype.Simple: Executortype; Pelaksana pelaksana; if (executorpe.batch == executorType) {executor = new Batchexecutor (this, transaction); } else if (executorpe.reuse == executortype) {executor = baru reuseexecutor (this, transaction); } else {executor = new SimpleExecutor (this, transaction); } if (cacheenabled) {executor = new CachingExecutor (Executor, AutoCommit); } Executor = (Executor) IntercepTorchain.pluginall (Executor); mengembalikan pelaksana;}4 metode di atas adalah semua metode konfigurasi. Metode -metode ini akan dijalankan dalam operasi mybatis (Tambah, Hapus, Modifikasi, dan Permintaan). Urutan eksekusi adalah pelaksana, ParameterHandler, hasilSethandler, Pernyataan Handler (di mana ParameterHandler dan HasilSethandler diciptakan saat membuat Pernyataan Handler [3 Kelas Implementasi yang Tersedia CallableStatementHandler, Persiapan StateTatementhandler, SimpleStateHandler], dan Konstruktor menyebut Konstruktor [Konstruktor dari Tiga Kelas Implementasi ini benar -benar memanggil Konstruktor PUTIT PUTIT
Setelah 4 metode ini instantiate objek yang sesuai, mereka akan memanggil metode pluginall dari interceptorchain. Seperti yang disebutkan sebelumnya, pluginall dari InterceptorChain telah diperkenalkan, yaitu untuk melintasi semua pencegat dan kemudian memanggil metode plugin dari setiap pencegat. Catatan: Nilai pengembalian metode plugin pencegat akan ditetapkan langsung ke objek asli.
Karena Pernyataan Tulisan dapat dicegat, antarmuka ini terutama berkaitan dengan konstruksi sintaks SQL. Oleh karena itu, misalnya, fungsi paging dapat diimplementasikan dengan pencegat. Anda hanya perlu memproses SQL di kelas Implementasi Antarmuka Pernyataan Handler dalam metode plugin Interceptor, dan Anda dapat menggunakan refleksi untuk mengimplementasikannya.
MyBatis juga memberikan anotasi untuk @Intercepts dan @signature tentang pencegat. Contoh situs web resmi adalah menggunakan dua anotasi ini, termasuk penggunaan kelas plugin:
Plugin Objek @Overridepublic (Target Objek) {return plugin.wrap (target, this);}Mari kita analisis kode sumber dari 3 "kombinasi baru" ini. Pertama, mari kita lihat metode bungkus kelas plugin:
Bungkus Objek Statis Publik (Target Objek, Interceptor Interceptor) {MAP <Class <?>, Set <nethod>> SignatureMap = getSignatureMap (Interceptor); Kelas <?> Type = target.getClass (); Kelas <?> [] Antarmuka = getAllInterfaces (type, SignatureMap); if (interfaces.length> 0) {return proxy.newproxyInstance (type.getClassLoader (), antarmuka, plugin baru (target, antarmuka, SignatureMap)); } return target;}Kelas plugin mengimplementasikan antarmuka InvocationHandler. Jelas, kita melihat bahwa kelas proxy dinamis yang disediakan oleh JDK sendiri dikembalikan ke sini. Mari membedah metode lain yang dipanggil dengan metode ini:
Metode getignatureMap:
Private Static Map <class <?>, Set <tethod>> getignatureMap (interceptor interceptor) {intercepts interceptSannotation = interceptor.getClass (). getAnnotation (intercepts.class); if (interceptSannotation == null) {// edisi #251 lempar pluginexception baru ("no @Intercepts anotasi ditemukan di interceptor" + interceptor.getClass (). getName ()); } Signature [] sigs = interceptSannotation.value (); Peta <class <?>, Atur <pet Method>> SignatureMap = hashmap baru <class <?>, Atur <nethod>> (); untuk (Signature Sig: SIGS) {set <method> Method = SignatureMap.get (sig.type ()); if (Methods == null) {Methods = Hashset baru <method> (); SignatureMap.put (sig.type (), metode); } coba {metode metode = sig.type (). getMethod (sig.method (), sig.args ()); Methods.add (Metode); } catch (nosuchmethodeException e) {lempar pluginexception baru ("tidak dapat menemukan metode pada" + sig.type () + "bernama" + sig.method () + ". Penyebab:" + e, e); }} return SignatureMap;}Metode GetignatureMap Penjelasan: Pertama, Anda akan mendapatkan anotasi @Interceptor dari kelas pencegat, kemudian dapatkan koleksi anotasi @signature dari atribut anotasi ini, kemudian melintasi koleksi ini, mengambil atribut tipe (tipe kelas) dari @signature annotation, dan kemudian mendapatkan metode dengan atribut metode dan ARRIBUT ARGS ini berdasarkan tipe @Signature. Karena atribut @Signature dianotasi oleh @Interceptors adalah properti, pada akhirnya akan mengembalikan peta dengan tipe sebagai kunci dan nilai sebagai set <nethod>.
@Intercepts ({@Signature (type = executor.class, method = "update", args = {mappedstatement.class, object.class})})Misalnya, anotasi @Interceptors akan mengembalikan kunci sebagai pelaksana dan nilai sebagai koleksi (hanya ada satu elemen dalam koleksi ini, yaitu, contoh metode, contoh metode ini adalah metode pembaruan dari antarmuka pelaksana, dan metode ini memiliki parameter tipe pemetaan dan objek). Contoh metode ini diperoleh berdasarkan metode dan atribut ARGS @Signature. Jika parameter ARGS tidak sesuai dengan metode metode tipe tipe, pengecualian akan dilemparkan.
Metode GetAllInterfaces:
Private Static Class <?> [] getAllInterfaces (class <?> Type, peta <class <?>, set <nethod>> SignatureMap) {set <class <? >> antarmuka = hashset baru <class <? >> (); while (type! = null) {for (class <?> c: type.getInterfaces ()) {if (SignatureMap.containsKey (c)) {antarmuka.add (c); }} type = type.getSuperclass (); } return interfaces.toArray (kelas baru <?> [interfaces.size ()]);}Metode GetAllInterfaces Penjelasan: Menurut target instance target (target ini adalah kelas yang dapat dicegat oleh MyBatis Interceptor seperti yang disebutkan sebelumnya, pelaksana, ParameterHandler, hasilnya, Pernyataan Tulisan) dan kelas induknya, kembalikan array antarmuka yang berisi implementasi target dalam SignatureMap.
Oleh karena itu, fungsi kelas plugin adalah untuk mendapatkan atribut @signature array dari atribut beranotasi berdasarkan anotasi @Interceptors, dan kemudian menggunakan refleksi untuk menemukan metode yang sesuai sesuai dengan jenis, metode, dan atribut ARGS dari masing -masing @signature beranotasi. Akhirnya, berdasarkan antarmuka yang diimplementasikan oleh objek target yang dipanggil, putuskan apakah akan mengembalikan objek proxy untuk mengganti objek target asli.
Misalnya, di situs web resmi MyBatis, ketika konfigurasi memanggil metode NewExecutor, metode pembaruan (MappedStatement, parameter objek) dari antarmuka pelaksana dicegat oleh pencegat. Jadi akhirnya dikembalikan dengan plugin kelas proxy, bukan pelaksana. Saat memanggil metode dengan cara ini, jika itu adalah kelas proxy, itu akan dieksekusi:
Invoke Objek Publik (Proxy Objek, Metode Metode, Objek [] args) melempar Throwable {try {set <method> Method = SignatureMap.get (method.getDeclaringClass ()); if (metode! = null && methods.contains (metode)) {return interceptor.intercept (doa baru (target, metode, args)); } return method.invoke (target, args); } catch (exception e) {throw exceptionutil.unwrapthrowable (e); }}Itu benar, jika metode yang sesuai ditemukan dan proxyed, metode interseptor dari antarmuka interceptor akan dieksekusi.
Kelas doa ini adalah sebagai berikut:
doa kelas publik {target objek pribadi; metode metode pribadi; objek pribadi [] args; doa publik (target objek, metode metode, objek [] args) {this.target = target; this.method = metode; this.args = args; } objek publik getTarget () {return target; } Metode publik getMethod () {Metode pengembalian; } objek publik [] getArgs () {return args; } Objek Public Proceed () melempar InvocationTargetException, IllegalAccessException {return Method.invoke (target, args); }}Metode prosesnya adalah memanggil metode asli (tanpa proxy).
Meringkaskan
Di antara 3 metode yang disediakan oleh Mybatis Interceptor Interface, metode plugin digunakan dalam proses konstruksi prosesor tertentu (penangan). Metode Interceptor digunakan untuk menangani eksekusi kelas proxy. Metode SetProperties digunakan untuk mengatur properti pencegat.
Bahkan, metode yang disediakan oleh situs web resmi MyBatis untuk menggunakan @Interceptors dan @signature anotations dan kelas plugin untuk menangani pencegat tidak harus digunakan secara langsung dengan cara ini. Kami juga dapat meninggalkan ketiga kelas ini dan secara langsung melakukan operasi yang sesuai berdasarkan jenis instance target dalam metode plugin.
Secara keseluruhan, Mybatis Interceptor masih sangat sederhana. Interceptor sendiri tidak membutuhkan terlalu banyak poin pengetahuan, tetapi mempelajari interseptor membutuhkan keakraban dengan setiap antarmuka di Mybatis, karena pencegat melibatkan titik -titik pengetahuan dari setiap antarmuka.
Meringkaskan
Di atas adalah eksplorasi prinsip -prinsip Mybatis Interceptor yang diperkenalkan oleh editor. Saya harap ini akan membantu semua orang. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas semua orang tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!