1. Ikhtisar
Dalam sistem umum, ketika kami melakukan beberapa operasi penting, seperti masuk ke sistem, menambahkan pengguna, menghapus pengguna, dll., Kita perlu bertahan perilaku ini. Dalam artikel ini, kami menerapkan penyisipan log melalui anotasi khusus Spring AOP dan Java. Solusi ini memiliki sedikit gangguan pada bisnis asli dan lebih fleksibel dalam mewujudkan
2. Definisi kelas log terkait
Kami abstrak log ke dalam dua kelas: modul fungsional dan jenis operasi
Gunakan kelas enumerasi untuk menentukan modul fungsi modul moduletype, seperti modul siswa dan pengguna
Public Enum Moduletype {default ("1"), // Student Nilai Default ("2"), // Guru Modul Siswa ("3"); // Modul Pengguna Moduletype Private (Indeks String) {this.module = index; } Modul String Pribadi; Public String getModule () {return this.module; }}Gunakan kelas enumerasi untuk menentukan jenis operasi: EventType. Seperti login, tambah, hapus, perbarui, hapus, dll.
Public Enum EventType {default ("1", "default"), add ("2", "add"), update ("3", "update"), delete_single ("4", "delete-single"), login ("10", "login"), login_out ("11", "LOGIN_OUT"); Private EventType (String Index, String Name) {this.name = name; this.event = index; } Private String Event; nama string pribadi; Public String getEvent () {return this.event; } public string getName () {return name; }}3. Tentukan anotasi terkait log
3.1. @Logenable
Di sini kami menentukan jumlah sakelar log. Hanya ketika nilai ini benar di kelas, fungsi log di kelas ini akan diaktifkan.
@Didokumentasikan @retensi (retentionpolicy.runtime) @target ({elementType.type}) public @interface logeNable { / ** * Jika benar, logevent di bawah kelas akan diaktifkan, jika tidak * @return * / boolean logenable () default true;}3.2. @Logevent
Definisi log di sini. Jika anotasi ini dianotasi pada kelas, parameter ini digunakan sebagai nilai default untuk semua metode kelas. Jika anotasi pada metode ini, itu hanya akan berfungsi untuk metode ini
@Didokumentasikan@retention (retentionpolicy.runtime) @target ({java.lang.annotation.elementType.method, elementType.type}) public @interface logevent {moduletype module () default moduletype.default; // Modul yang dimiliki log milik EventType Event () Default EventType.Default; // Log Event Type String desc () default ""; // Deskripsi Informasi}3.3. @Logkey
Jika anotasi ini pada suatu metode, parameter seluruh metode disimpan ke format log dalam JSON. Jika anotasi ini dianotasi pada metode dan kelas, anotasi pada metode menimpa nilai pada kelas.
@Target ({elementType.field, elementType.parameter})@retention(RetensiPolicy.runtime)@documentedpublic @interface Logkey {string keyname () default ""; // Nama Kunci Boolean isUserId () default false; // Apakah bidang ini adalah userid dari operasi ini, di sini dihilangkan boolean islog () default true; // apakah itu ditambahkan ke log}4. Tentukan kelas pemrosesan log
4.1. Logadmmodel
Tentukan kelas yang menyimpan informasi log
LogAdMmodel kelas publik {Private Long ID; Private String UserID; // mengoperasikan nama pengguna string pribadi pengguna; Private String AdmModel; // Modul Private String AdmEvent; // Operasi tanggal pribadi dibuat; // konten operasi string privat advoptcontent; // Konten Operasi Private String Desc; // Pernyataan set/dapat dihilangkan}4.2. IlogManager
Tentukan IlogManager kelas antarmuka untuk pemrosesan log
Kami dapat menyimpan log dalam database, atau mengirim log untuk membuka middleware, jika redis, mq, dll. Setiap kelas pemrosesan log adalah kelas implementasi antarmuka ini
Antarmuka publik IlogManager { / *** Modul pemrosesan log* @param paramlogadmbean* / void deallog (logadmmodel paramlogadmbean);}4.3. DBlogManager
Kelas Implementasi IlogManager untuk menyimpan log. Hanya penyimpanan disimulasikan di sini
@ServICEPUBLIC Kelas DBlogManager mengimplementasikan IlogManager {@Override public void deallog (logadmmodel paramlogadmbean) {System.out.println ("Simpan log ke dalam database, konten log adalah sebagai berikut:" + json.tojsonstring (paramlogadmbean)); }}5. Konfigurasi AOP
5.1. Logaspect mendefinisikan kelas AOP
Anotasi kelas ini dengan @Aspect
Gunakan @pointcut untuk menentukan metode paket dan kelas untuk mencegat
Kami menggunakan @Around untuk menentukan metode
@Component @aspectpublic class logaspect {@Autowired private LoginFogeneration Loginfogeneration; @Autowired Private IlogManager LogManager; @Pointcut ("Eksekusi (*com.hry.spring.mvc.aop.log.service ..*.*(..))") public void ManagerLogpoint () {} @around ("ManagerLogpoint ()") Objek publik di sekitar METRAMANGERLOGPOint (rROCERINGJOINPOINT JP) melempar {... }} AiruteManagerLogpoint: Proses bisnis utama dari metode utama
1. Periksa apakah kelas metode pencegat dianotasi oleh @logenable. Jika demikian, logika log akan diikuti, jika tidak, logika normal akan dieksekusi.
2. Periksa apakah metode intersep adalah @LogEvent. Jika demikian, logika log akan diikuti, jika tidak logika normal akan dieksekusi.
3. Dapatkan nilai median @LogEvent berdasarkan metode yang diperoleh dan menghasilkan beberapa parameter log. Nilai @LogEvent didefinisikan pada kelas sebagai nilai default
4. Panggilan Loginfogeneration's ProcessManagerLogMessage untuk mengisi parameter lain dalam log. Kami akan berbicara tentang metode ini nanti.
5. Lakukan panggilan bisnis normal
6. Jika eksekusi berhasil, LogManager mengeksekusi log (kami hanya merekam log eksekusi yang berhasil di sini, dan Anda juga dapat menentukan log perekaman yang gagal)
@Around ("ManagerLogpoint ()") Objek Publik Objek AirweatagerLogpoint (ProsidingJoINPoint JP) melempar Throwable {class target = jp.getTarget (). GetClass (); // Dapatkan logEnable logEnable LogeNable = (logEnable) target.getAnnotation (logEnable.class); if (logeNable == null ||! logeNable.logenable ()) {return jp.proed (); } // Dapatkan logevent pada kelas sebagai nilai default logevent logeventclass = (logevent) target.getannotation (logevent.class); Metode metode = getInvokedMethod (jp); if (Method == null) {return jp.proed (); } // Dapatkan logevent pada metode logevent logeventMethod = method.getannotation (logevent.class); if (logEventMethod == null) {return jp.proed (); } String optevent = logeventmethod.event (). GetEvent (); String optModel = logeventMethod.module (). GetModule (); String desc = logeventmethod.desc (); if (logEventClass! = null) {// Jika nilai pada metode ini adalah nilai default, ganti dengan nilai global. OPTEVENT = OPTEVENT.Equals (EventType.Default)? LogEventClass.event (). GetEvent (): OppEvent; OptModel = OptModel.Equals (Moduletype.Default)? logeventclass.module (). getModule (): OptModel; } LogAdMmodel LogBean = LogAdMModel baru (); logbean.setadmmodel (optModel); Logbean.setAdMevent (OPTEVENT); logbean.setdesc (desc); logbean.setCreateDate (tanggal baru ()); LoginFogeneration.ProcessingManagerLogMessage (JP, Logbean, Metode); Objek returnObj = jp.proed (); if (optevent.equals (eventType.login)) {// todo jika masuk, Anda perlu menilai apakah itu berhasil berdasarkan nilai pengembalian. Jika berhasil, maka tambahkan log. Penilaian di sini relatif sederhana jika (returnobj! = Null) {this.logManager.deallog (logbean); }} else {this.logManager.deallog (logbean); } return returnobj; } / ** * Dapatkan metode permintaan * * @param jp * @return * / metode publik getInvokedMethod (joinpoint jp) {// parameter daftar metode panggilan classlist = new arraylist (); untuk (objek obj: jp.getArgs ()) {classlist.add (obj.getClass ()); } Class [] argscls = (class []) classlist.toArray (kelas baru [0]); // Metode yang disebut string MethodName = jp.getSignature (). GetName (); Metode metode = null; coba {method = jp.getTarget (). getClass (). getMethod (methodName, argscls); } catch (nosuchmethodeException e) {e.printstacktrace (); } metode pengembalian; }}6. Solusi untuk menerapkan solusi di atas dalam praktiknya
Di sini kami mensimulasikan bisnis siswa, dan menggunakan anotasi di atas untuk menerapkannya kepada mereka dan mencegat log.
6.1. Istudentservice
Kelas Antarmuka Bisnis, Jalankan Umum CRUD
Public Interface iStudentService {void deleteById (ID String, String a); int save (StudentModel StudentModel); pembaruan void (StudentModel StudentModel); void queryById (string id);}6.2. SiswaServiceImpl:
@Logenable: @LogEvent mendefinisikan semua metode modul pada kelas intersepsi log startup. Informasi lain tentang @Logeven mendefinisikan log. @Service @logeNable // Mulai log intersepsi @LogEvent (module = moduletype.student) kelas publik SiswaServiceImpl mengimplementasikan ISTudentService {@Override @LogEvent (event = eventType.delete_single, desc = "hapus catatan") // tambahkan log pengenal publik void delete deletyid) {delete ") System.out.printf (this.getClass () + "deletebyid id =" + id); } @Override @LogEvent (event = eventType.add, desc = "save record") // Tambahkan log pengidentifikasi int int save (studentmodel studentmodel) {System.out.printf (this.getClass () + "save save =" + json.toJsonstring (studentModel)); kembali 1; } @Override @LogEvent (event = eventType.update, desc = "Update Record") // Tambahkan Log Identifier Public Void Update (StudentModel StudentModel) {System.out.printf (this.getClass () + "Save Update =" + Json.toJsonstring (StudentModel)); } // Tidak ada log pengidentifikasi @Override public void queryById (string id) {System.out.printf (this.getClass () + "queryById id =" + id); }}Jalankan kelas uji dan cetak informasi berikut untuk menunjukkan bahwa konfigurasi anotasi log kami diaktifkan:
Simpan log ke dalam database, dan konten log adalah sebagai berikut:
{"AdmEvent": "4", "AdmModel": "1", "AdmOptContent": "{/" id/":/" 1/"}", "created": 1525779738111, "desc": "hapus catatan"}7. Kode
Lihat di bawah untuk kode terperinci di atas
Kode GitHub, coba gunakan tag v0.21, jangan gunakan master, karena saya tidak dapat menjamin bahwa kode master akan tetap tidak berubah