Persyaratan fungsional adalah bahwa perusahaan perlu membangun platform operasi yang besar:
1. Platform Operasi memiliki basis data sendiri, mempertahankan fungsi dasar seperti pengguna, peran, menu, suku cadang dan izin.
2. Platform Operasi juga perlu menyediakan operasi back-end dari berbagai layanan lainnya (Layanan A, Layanan B), dan database Layanan A dan Layanan B independen.
Oleh karena itu, platform operasi harus menghubungkan setidaknya tiga pustaka: pustaka operasi, perpustakaan A, dan perpustakaan B, dan berharap untuk secara otomatis beralih ke sumber data yang sesuai untuk setiap permintaan fungsi (implementasi akhir saya adalah beralih ke tingkat metode layanan, dan untuk beralih ke metode setiap lapisan DAO. Fungsi sistem kami relatif independen satu sama lain).
Langkah 1: Mengkonfigurasi beberapa sumber data
1. Tentukan sumber data:
Sumber data yang saya gunakan adalah DruidDataSource Alibaba (tidak masalah dengan DBCP, ini apa pun). Konfigurasinya adalah sebagai berikut:
<!-OP DataSource-> <bean id = "opdataSource" init-method = "init" destroy-metod = "tutup"> <nama properti = "url" value = "$ {db.master.url}" /> <nama properti = "username" value = "$ {db.master.user}" / value = "$ {db.master.password}" /> <name properti = "driverclassname" value = "$ {db.master.driver}" /> <name properti = "inisialisasi" nilai = "5" /> <nama properti = "MaxActive" value = "100" /> <name properti = "500" "value =" "value =" "value =" value = "100" /> <name properti = "Minidle" value = "" name = "" "" name = "" value = "" value = "a name =" a name = "a name =" a name = "name =" MIXACTIVE "name =" 100 " name = "validationQuery" value = "pilih 'x'" /> <name properti = "testonborrow" value = "false" /> <properti name = "testonreturn" value = "false" /> <name properti = "testwhileIdle" value = "true" /> <name properti = "timeBeteVictionRunsmillis" value = "600000" value = "300000" /> <name properti = "removeAbandoned" value = "true" /> <name properti = "removeAbandOndTimeOut" value = "1800" /> <name properti = "logabandoned" value = "true" /<!-Konfigurasi filter untuk pemantauan statistik intersept name = "ConnectionProperties" value = "config.decrypt = true" /> </ bean> <!-servera dataSource-> <bean id = "serveradataSource" init-method = "init" wrash-method = "close"> <property name = "url" value = "$ {db.servera.master.master. value = "$ {db.servera.master.user}" /> <name properti = "kata sandi" value = "$ {db.servera.master.password}" /> <nama properti = "driverclassname" value = "$ {db.servera.master.driver}" /<nama properti = "$" "" "" Nilai "" Nilai "" Nilai "" Nilai "" Nilai "" Nilai "" Nilai "" /> <property name="minIdle" value="10" /> <property name="maxWait" value="60000" /> <property name="validationQuery" value="SELECT 'x'" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testOnReturn" value="false" /> <property name="testOnReturn" value = "false" /> <name properti = "testwhileIdle" value = "true" /> <name properti = "timebetweenevictionrunsmillis" value = "600000" /> <name properti = "MinEvictableIdeLletImeMillis" value = "300000" /<nama properti = "RemoveBandoned" value = "tro propert" /> <300000 " /> <nama properti =" removeAbandoned "value =" true "" /> <po properten " /> <po properten" name = "REPOVAABANDONED" value = "true" " /<po property" /> <po properten "" <nama properti = "Logabandoned" value = "true" /> <!-Mengkonfigurasi filter untuk pemantauan statistik intersep-> <name properti = "filter" value = "config, gregestat, wall, log4j2" /> <name properti = "server connection" value = "config.decrypt = true" /< /beAs> < /serverboor "server =" DATCCE. init-method = "init" destroy-method = "tutup"> <name properti = "url" value = "$ {db.serverb.master.url}" /> <name properti = "username" value = "$ {db.server.master.user}" /<properti name = "kata sandi" value = "$ {dwors.paster. name = "driverclassName" value = "$ {db.serverb.master.driver}" /> <name properti = "inisialisasi" value = "5" /> <name properti = "MaxActive" value = "100" /> <nama properti = "MinIdle" value = "10" /> <Properti Nama = "MaxWait" NOVE "600" 600 "NAME" /"10" /> <Properti Nama = "MAXWAIT" NOVE "600 =" 600 (600. "NOVE" /10 " /> <nama properti = "testonborrow" value = "false" /> <properti name = "testonreturn" value = "false" /> <name properti = "testwhileIdle" value = "true" /> <name properti = "timebetweeneVictionrunsmillis" value = "600000" /> <name Property = "Minevictabicablis =" 600000 " /<Property Name =" MINEVICTABLISEON = "Nilai" 300000 " value = "true" /> <name properti = "removeAbandOnDtimeout" value = "1800" /> <name properti = "logabandoned" value = "true" /> <!-Konfigurasikan filter untuk pemantauan statistik intersep-> <name properti = "value" connect "config, wall, log4j2" /<name property = "value =" connection "value =" value "value =" name. "connectat, wall, log4j2" /<a name = "coneksi =" </tagel>Saya mengonfigurasi tiga sumber data: OpDataSource (sumber data platform operasi itu sendiri), ServeradataSource, dan ServerBDataSource.
2. Konfigurasikan MultipledataSource
MultipledataSource setara dengan satu proksi untuk tiga sumber data di atas. Ketika itu benar -benar dikombinasikan dengan pegas/mybatis, multipleDataSource dan penggunaan data data yang dikonfigurasi secara terpisah tidak berbeda:
<!-Integrasi Musim Semi MyBatis: Mengkonfigurasi MultipledataSource-> <bean id = "sqlSessionFactory"> <name properti = "dataSource" ref = "multipleDataSource"/> <!-secara otomatis memetakan. <value> classpath*:/sqlmapperxml/*/*. xml </ value> </cist> </propert> <properti name = "configLocation" value = "classpath: xml/mybatis-config.xml"> </preate> <properti nama = "TypealiSespackage" value = "com.xx" </properte "/typealisespackage" value = "com.xx. ref="globalConfig" /> <property name="plugins"> <array> <!-- Pagination plugin configuration--> <bean id="paginationInterceptor" > <property name="dialectType" value="mysql" /> <property name="optimizeType" value="aliDruid" /> </bean> </array> </property> </bean> <!-- MyBatis dynamic implementation --> <bean id="mapperScannerConfigurer"> <!-- For Dao interface dynamic implementation, you need to know where the interface is --> <property name="basePackage" value="com.XXX.platform.mapper" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- MP global configuration --> <bean id="globalConfig"> <property name="idType" value="0" /> <property name="dbColumnUnderline" value="true" /> </bean> <!-- Transaction Management Configuration multipleDataSource --> <bean id="transactionManager" > <property name="dataSource" ref="multipleDataSource"></property> </bean>
Setelah memahami lokasi MultipledataSource, mari kita fokus pada bagaimana menerapkan MultipledataSource. File konfigurasi adalah sebagai berikut:
<bean id = "multipleDataSource"> <name properti = "defaultTargetDataSource" ref = "opdataSource" /> <name properti = "targetDataSources"> <MAP> <entri key = "OpDataSource" value = "OpDataSource" /<Entry Key = "ServerAsource" Value = "OpDataSource" /<Entry Key = "ServerAsource" Value = "OpDataSource" /<Entry Key = "ServerAsource" Value "Nilai "on" KEY = "ServerBDataSource" Value-Ref = "ServerBDataSource"/> </peta> </prively> </tean>
Kode Java yang diimplementasikan adalah sebagai berikut, dan tidak perlu terlalu banyak penjelasan, dan sangat jelas dalam sekejap:
Impor org.springframework.jdbc.datasource.lookup.abstractroutingDataSource;/** * * @classname: MultipledataSource * @description: Konfigurasikan beberapa sumber data <br> * @Author: yuzhu.peng * @date: Januari 12, 2018 AT 2018 AT 2018 AT 2018 AT 2018: yuzhu.peng * @date: Januari 12, 2018 AT 2018 AT 2018 AT 20118: yuzhu.peng * @date: Januari 12, 2018 AT 2018 AT 20118 AT 20118: yuzhu.peng * @date: Januari 12, 2018 AT 2018 AT 20118 AT 20118: YUZHU. AbstractroutingDataSource {private static final threadlocal <string> datasourceye = new OncolableThreadlocal <String> (); public static void setDataSourCekey (String DataSource) {DataSourCey.set (DataSource); } @Override Protected Object DetectionEcurrentLookUpkey () {return DataSourCey.get (); } public static void RemovedataSourCeye () {DataSourCey.Remove (); }}Diwarisi dari SpractroutingDataSource Spring, mengimplementasikan metode abstrak determinecurrentlookupkey. Metode ini akan menentukan sumber data sumber data untuk koneksi ini setiap kali koneksi database diperoleh. Anda dapat melihat kode pegas lebih jelas:
/*Dapatkan koneksi*/ koneksi publik getConnection () melempar sqlexception {return detectInetargetDataSource (). GetConnection (); } DataSource yang dilindungi determInetargetDataSource () {assert.notnull (this.resolvedDataSources, "router DataSource tidak diinisialisasi"); /*DeterminecurrentLookUpkey Berikut adalah antarmuka abstrak, memperoleh nama sumber data spesifik*/ objek lookupkey = determinecurrentLookUpkey (); DataSource DataSource = (DataSource) this.resolvedDataSources.get (lookUpkey); if ((DataSource == null) && (((this.lenientfallback) || (lookupkey == null)))) {DataSource = this.resolvedDefaultDataSource; } if (DataSource == null) {lempar baru ilegalstateException ("tidak dapat menentukan sumber data target untuk kunci pencarian [" + lookupkey + "]"); } return DataSource; } /*Abstrak Antarmuka: Artinya, antarmuka yang diimplementasikan oleh multipleDataSource* / abstrak abstrak kami DeterminecurrentLookUpkey ();Langkah 2: Secara dinamis beralih sumber data setiap permintaan (level metode layanan)
Gagasan implementasi adalah menggunakan ide AOP Spring untuk mencegat setiap panggilan metode layanan, dan kemudian secara dinamis mengganti kunci data dalam MultipleDataSource sesuai dengan nama jalur keseluruhan metode. Proyek kami, untuk operasi berbagai layanan, yaitu, basis data yang berbeda, tidak tergantung satu sama lain. Tidak disarankan untuk memanggil sumber data yang berbeda dalam metode layanan yang sama. Dengan cara ini, kita perlu secara dinamis menentukan apakah frekuensi switching perlu ditempatkan pada level DAO, yaitu level SQL. Selain itu, manajemen transaksi tidak nyaman.
Mari kita lihat implementasi AOP dari sumber data switching dinamis:
import java.lang.reflect.Proxy;import org.apache.commons.lang.ClassUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.core.annotation.Order;/** * Data source switching AOP * * @Author yuzhu.peng * @since 2018-01-15 * / @aspek @order (1) kelas publik MultipledataSourceinterceptor { /** * Interceptor memberikan perhatian khusus pada pengalihan sumber data sebelum meminta semua kelas implementasi bisnis. Karena beberapa sumber data digunakan, yang terbaik adalah memanggil Mapper hanya di *ServiceImpl. Kalau tidak, saat memanggil tabel yang bukan sumber data default, pengecualian yang tidak ada dalam tabel akan dilaporkan** @param goinpoint* @throws lempar*/ @before ("eksekusi (* com.xxxx.platform.service ..*.* ServiceImpl.* (..)") public void setDatauce publ {loMPoPPOint = LOMPOPON = LOMPOIND/ LOMPOPLOZE/ LOMPOPLOZE/ LOMPOPLOZE/ LOMPOPLOZE/ LOMPOPLOZE (LOMPOPON (..) ") Public Void PubliZen (LOMPOPON (..)) joinpoint.getarget (). getClass (); String className = clazz.getName (); if (classutils.isassignable (clazz, proxy.class)) {className = joinpoint.getSignature (). getDeclaringTypeName (); } // Atur sumber data Servera dengan nama kelas, jika tidak defaultnya adalah sumber data di latar belakang IF (className.contains (". Servera.")) {MultipledataSource.setDataSourcekey (dbconstant.data_source_servera); } else if (classname.contains (". serverb.")) {multipleDataSource.setDataSourcey (dbconsant.data_source_serverb); } else {multipleDataSource.setDataSourcey (dbconsant.data_source_op); }} /*** Ketika operasi selesai, jika sumber data saat ini dirilis, jika tidak dirilis, konflik sumber data akan terjadi saat mengklik sering. Ini adalah tabel sumber data lain, tetapi akan berjalan ke sumber data lain. Laporan ini tidak ada** @param goinpoint* @throws Throwable*/ @after ("Eksekusi (* com.xxxx.service ..*.* ServiceImpl.* (..))") void public dihapus raidatauce (joinpoint joinpoint) melempar {multipleDataSource.removedataSource (); }}Mencegat semua metode layanan, menilai fungsi sumber data mana yang termasuk dalam nama metode yang sepenuhnya memenuhi syarat, dan kemudian pilih sumber data yang sesuai. Setelah distribusi selesai, lepaskan sumber data saat ini. Perhatikan bahwa saya menggunakan Spring's @order, anotasi, dan saya akan membicarakannya selanjutnya, ketika mendefinisikan beberapa AOP, pesanan sangat berguna.
lainnya:
Pada awalnya, proyek tidak memperkenalkan transaksi, jadi semuanya baik -baik saja. Anda dapat mengakses sumber data yang benar setiap saat. Setelah bergabung dengan manajemen transaksi pegas, Anda tidak dapat secara dinamis mengganti sumber data (tampaknya transaksi tidak efektif, tetapi keduanya tidak valid pada saat yang sama). Kemudian, saya menemukan bahwa alasannya adalah perintah eksekusi AOP, jadi saya menggunakan urutan pegas yang disebutkan di atas:
Semakin kecil pesanan, eksekusi adalah yang pertama. Pada titik ini, Anda tidak hanya dapat mengganti sumber data secara dinamis, tetapi juga berhasil menggunakan transaksi (dalam sumber data yang sama).
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.