Saya melalui situasi yang sangat menarik di tempat kerja dan saya ingin berkongsi penyelesaiannya di sini.
Bayangkan anda perlu memproses satu set data. Dan untuk menangani set data ini, anda mempunyai beberapa strategi berbeza untuk ini. Contohnya, saya perlu mencipta strategi untuk cara mengambil koleksi data daripada S3, atau contoh dalam repositori setempat, atau diluluskan sebagai input.
Dan sesiapa yang akan menentukan strategi ini adalah orang yang membuat permintaan:
Saya ingin mendapatkan data dalam S3. Ambil data yang dijana pada hari X antara jam H1 dan H2, iaitu daripada klien Abóbora. Dapatkan 3000 data terakhir yang memenuhi ini.
Atau sebaliknya:
Ambil data contoh yang anda ada di sana, salin 10000 kali untuk melakukan ujian tekanan.
Atau pun:
Saya mempunyai direktori ini, anda juga mempunyai akses kepadanya. Dapatkan segala-galanya dalam direktori itu dan secara rekursif ke dalam subdirektori.
Dan juga akhirnya:
Ambil unit data ini yang terdapat dalam input dan gunakannya.
Bagaimana untuk melaksanakan?
Fikiran pertama saya ialah: "bagaimana saya boleh menentukan bentuk input saya dalam Java?"
Dan saya mencapai kesimpulan pertama, sangat penting untuk projek: "anda tahu apa? Saya tidak akan menentukan bentuk. Tambah Peta
Selain itu, kerana saya tidak meletakkan sebarang bentuk dalam DTO, saya mempunyai kebebasan sepenuhnya untuk mencuba input.
Jadi selepas mewujudkan bukti konsep, kita sampai pada situasi: kita perlu keluar daripada tekanan POC dan beralih kepada sesuatu yang hampir dengan penggunaan sebenar.
Perkhidmatan yang saya lakukan adalah untuk mengesahkan peraturan. Pada asasnya, apabila menukar peraturan, saya perlu mengambil peraturan itu dan memadankannya dengan peristiwa yang berlaku dalam aplikasi pengeluaran. Atau, jika aplikasi telah ditukar dan tiada pepijat, jangkaan ialah keputusan untuk peraturan yang sama akan kekal sama untuk data yang sama; Sekarang, jika keputusan untuk peraturan yang sama menggunakan set data yang sama diubah... nah, itu potensi masalah.
Jadi, saya memerlukan aplikasi ini untuk menjalankan ujian belakang peraturan. Saya perlu menekan aplikasi sebenar yang menghantar data untuk penilaian dan peraturan yang dipersoalkan. Penggunaan ini agak pelbagai:
- sahkan potensi penyelewengan apabila mengemas kini aplikasi
- sahkan sama ada peraturan yang diubah mengekalkan tingkah laku yang sama
- contohnya, mengoptimumkan masa pelaksanaan peraturan
- semak sama ada perubahan dalam peraturan menjana perubahan yang dijangkakan dalam keputusan
- sahkan bahawa perubahan dalam aplikasi sebenarnya menjadikannya lebih cekap
- contohnya, menggunakan versi baharu GraalVM dengan JVMCI dihidupkan meningkatkan bilangan permintaan yang boleh saya buat?
Jadi, untuk itu, saya memerlukan beberapa strategi untuk asal usul peristiwa:
- dapatkan data sebenar daripada S3
- ambil data yang menjadi sampel dalam repositori dan salinnya beberapa kali
- dapatkan data dari lokasi tertentu pada mesin tempatan saya
Dan saya juga memerlukan strategi yang berbeza daripada peraturan saya:
- lulus melalui input
- menggunakan rintisan yang berjalan pantas
- menggunakan sampel berdasarkan peraturan pengeluaran
- gunakan laluan ini di sini pada mesin saya
Bagaimana untuk menangani perkara ini? Baiklah, biarkan pengguna memberikan data!
API untuk Strategi
Adakah anda tahu sesuatu yang selalu menarik perhatian saya tentang json-schema? Ini di sini:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { //... } }
Medan ini bermula dengan $. Pada pendapat saya, mereka digunakan untuk menunjukkan metadata. Jadi mengapa tidak gunakan ini dalam input data untuk menunjukkan metadata strategi mana yang sedang digunakan?
{ "dados": { "$strategy": "sample", "copias": 15000 }, //... }
Sebagai contoh, saya boleh memesan 15000 salinan data yang saya ada sebagai sampel. Atau minta beberapa perkara daripada S3, membuat pertanyaan dalam Athena:
{ "dados": { "$strategy": "athena-query", "limit": 15000, "inicio": "2024-11-25", "fim": "2024-11-26", "cliente": "Abóbora" }, //... }
Atau dalam laluan setempat?
{ "dados": { "$strategy": "localpath", "cwd": "/home/jeffque/random-project-file", "dir": "../payloads/esses-daqui/top10-hard/" }, //... }
Jadi saya boleh mewakilkan kepada pemilihan strategi di hadapan.
Semakan kod dan fasad
Pendekatan pertama saya untuk menangani strategi ialah:
public DataLoader getDataLoader(Map<String, Object> inputDados) { final var strategy = (String) inputDados.get("$strategy"); return switch (strategy) { case "localpath" -> new LocalpathDataLoader(); case "sample" -> new SampleDataLoader(resourcePatternResolver_spring); case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client); default -> new AthenaQueryDataLoader(athenaClient, s3Client); } }
Jadi arkitek saya bertanya dua soalan semasa semakan kod:
- "mengapa anda membuat seketika segala-galanya dan tidak membiarkan Spring bekerja untuk anda?"
- dia mencipta DataLoaderFacade dalam kod dan meninggalkannya separuh masak
Apa yang saya faham daripada ini? Menggunakan fasad adalah idea yang baik untuk menyerahkan pemprosesan ke sudut yang betul dan... untuk melepaskan kawalan manual?
Nah, banyak keajaiban berlaku kerana Musim Bunga. Memandangkan kami berada di rumah Java dengan kepakaran Java, mengapa tidak menggunakan Java/Spring idiomatik, bukan? Hanya kerana Saya sebagai individu mendapati beberapa perkara sukar difahami tidak semestinya ianya rumit. Jadi, mari kita menghayati dunia sihir suntikan pergantungan Java.
Mencipta objek fasad
Apa dulu:
final var dataLoader = getDataLoader(inputDados) dataLoader.loadData(inputDados, workingPath);
Menjadi:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { //... } }
Jadi lapisan pengawal saya tidak perlu mengurus ini. Biarkan ia pada fasad.
Jadi, bagaimana kita akan membuat fasad? Nah, untuk memulakan, saya perlu menyuntik semua objek ke dalamnya:
{ "dados": { "$strategy": "sample", "copias": 15000 }, //... }
Ok, untuk DataLoader utama saya menulisnya sebagai @Primary sebagai tambahan kepada @Service. Selebihnya saya tulis sahaja dengan @Service.
Uji ini di sini, tetapkan getDataLoader untuk mengembalikan null hanya untuk mencuba cara Spring memanggil pembina dan... ia berfungsi. Sekarang saya perlu nota dengan metadata setiap perkhidmatan strategi yang mereka gunakan...
Bagaimana untuk melakukan ini...
Nah, lihat! Di Java kami mempunyai anotasi! Saya boleh mencipta anotasi masa jalan yang mempunyai di dalamnya strategi yang digunakan oleh komponen itu!
Jadi saya boleh mempunyai sesuatu seperti ini dalam AthenaQueryDataLoader:
{ "dados": { "$strategy": "athena-query", "limit": 15000, "inicio": "2024-11-25", "fim": "2024-11-26", "cliente": "Abóbora" }, //... }
Dan saya juga boleh mempunyai alias, mengapa tidak?
{ "dados": { "$strategy": "localpath", "cwd": "/home/jeffque/random-project-file", "dir": "../payloads/esses-daqui/top10-hard/" }, //... }
Dan tunjukkan!
Tetapi bagaimana untuk mencipta anotasi ini? Nah, saya memerlukannya untuk mempunyai atribut yang merupakan vektor rentetan (pengkompil Java sudah berurusan dengan menyediakan rentetan tunggal dan mengubahnya menjadi vektor dengan 1 kedudukan). Nilai lalai ialah nilai. Ia kelihatan seperti ini:
public DataLoader getDataLoader(Map<String, Object> inputDados) { final var strategy = (String) inputDados.get("$strategy"); return switch (strategy) { case "localpath" -> new LocalpathDataLoader(); case "sample" -> new SampleDataLoader(resourcePatternResolver_spring); case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client); default -> new AthenaQueryDataLoader(athenaClient, s3Client); } }
Jika medan anotasi bukan nilai, saya perlu menyatakannya dengan jelas dan itu akan kelihatan hodoh, seperti dalam anotasi EstrategiaFeia:
final var dataLoader = getDataLoader(inputDados) dataLoader.loadData(inputDados, workingPath);
Bunyinya tidak begitu natural pada pendapat saya.
Baiklah, memandangkan itu, kami masih memerlukan:
- ekstrak anotasi kelas daripada objek yang diluluskan
- buat peta rentetan → pemuat data (atau rentetan → T)
Mengekstrak anotasi dan memasang peta
Untuk mengekstrak anotasi, saya perlu mempunyai akses kepada kelas objek:
dataLoaderFacade.loadData(inputDados, workingPath);
Selain itu, bolehkah saya bertanya sama ada kelas ini diberi anotasi dengan anotasi seperti Strategi:
@Service // para o Spring gerenciar esse componente como um servi?o public class DataLoaderFacade implements DataLoader { public DataLoaderFacade(DataLoader primaryDataLoader, List<DataLoader> dataLoaderWithStrategies) { // armazena de algum modo } @Override public CompletableFuture<Void> loadData(Map<String, Object> input, Path workingPath) { return getDataLoader(input).loadData(input, workingPath); } private DataLoader getDataLoader(Map<String, Object> input) { final var strategy = input.get("$strategy"); // magia... } }
Adakah anda ingat bahawa ia mempunyai medan nilai? Nah, medan ini mengembalikan vektor rentetan:
@Service @Primary @Estrategia("athena-query") public class AthenaQueryDataLoader implements DataLoader { // ... }
Tunjukkan! Tetapi saya mempunyai cabaran, kerana sebelum ini saya mempunyai objek jenis T dan sekarang saya mahu memetakan objek yang sama ke dalam, baik, (T, String)[]. Dalam strim, operasi klasik yang melakukan ini ialah flatMap. Dan Java juga tidak membenarkan saya memulangkan tupel seperti itu entah dari mana, tetapi saya boleh mencipta rekod dengannya.
Ia akan kelihatan seperti ini:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { //... } }
Bagaimana jika terdapat objek yang tidak dianotasi dengan strategi? Adakah ia akan memberi NPE? Lebih baik tidak, mari kita menapisnya sebelum NPE:
{ "dados": { "$strategy": "sample", "copias": 15000 }, //... }
Memandangkan itu, saya masih perlu menyusun peta. Dan, lihatlah: Java sudah menyediakan pengumpul untuk ini! Collector.toMap(keyMapper, valueMapper)
{ "dados": { "$strategy": "athena-query", "limit": 15000, "inicio": "2024-11-25", "fim": "2024-11-26", "cliente": "Abóbora" }, //... }
Setakat ini, ok. Tetapi flatMap sangat mengganggu saya. Terdapat API Java baharu yang dipanggil mapMulti, yang mempunyai potensi untuk membiak:
{ "dados": { "$strategy": "localpath", "cwd": "/home/jeffque/random-project-file", "dir": "../payloads/esses-daqui/top10-hard/" }, //... }
Kecantikan. Saya mendapatkannya untuk DataLoader, tetapi saya juga perlu melakukan perkara yang sama untuk RuleLoader. Atau mungkin tidak? Jika anda perasan, tiada apa-apa dalam kod ini yang khusus untuk DataLoader. Kita boleh abstrak kod ini!!
public DataLoader getDataLoader(Map<String, Object> inputDados) { final var strategy = (String) inputDados.get("$strategy"); return switch (strategy) { case "localpath" -> new LocalpathDataLoader(); case "sample" -> new SampleDataLoader(resourcePatternResolver_spring); case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client); default -> new AthenaQueryDataLoader(athenaClient, s3Client); } }
Di bawah fasad
Atas sebab utilitarian semata-mata, saya meletakkan algoritma ini dalam anotasi:
final var dataLoader = getDataLoader(inputDados) dataLoader.loadData(inputDados, workingPath);
Dan untuk fasad? Nah, kerja yang baik untuk mengatakan perkara yang sama. Saya memutuskan untuk mengabstrak ini:
dataLoaderFacade.loadData(inputDados, workingPath);
Dan fasad kelihatan seperti ini:
@Service // para o Spring gerenciar esse componente como um servi?o public class DataLoaderFacade implements DataLoader { public DataLoaderFacade(DataLoader primaryDataLoader, List<DataLoader> dataLoaderWithStrategies) { // armazena de algum modo } @Override public CompletableFuture<Void> loadData(Map<String, Object> input, Path workingPath) { return getDataLoader(input).loadData(input, workingPath); } private DataLoader getDataLoader(Map<String, Object> input) { final var strategy = input.get("$strategy"); // magia... } }
Atas ialah kandungan terperinci Menggunakan anotasi dalam Java untuk membuat strategi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Terdapat tiga perbezaan utama antara yang boleh dipanggil dan boleh dijalankan di Jawa. Pertama, kaedah yang boleh dipanggil boleh mengembalikan hasilnya, sesuai untuk tugas -tugas yang perlu mengembalikan nilai, seperti yang boleh dipanggil; Walaupun kaedah run () runnable tidak mempunyai nilai pulangan, sesuai untuk tugas -tugas yang tidak perlu kembali, seperti pembalakan. Kedua, Callable membolehkan untuk membuang pengecualian yang diperiksa untuk memudahkan penghantaran ralat; Walaupun Runnable mesti mengendalikan pengecualian secara dalaman. Ketiga, Runnable boleh dihantar secara langsung ke benang atau executorservice, sementara yang boleh dipanggil hanya boleh dikemukakan ke executorservice dan mengembalikan objek masa depan untuk

Java menyokong pengaturcaraan asynchronous termasuk penggunaan aliran yang boleh diselesaikan, aliran responsif (seperti ProjectReactor), dan benang maya di Java19. 1.CompletableFuture meningkatkan kebolehbacaan dan penyelenggaraan kod melalui panggilan rantai, dan menyokong orkestrasi tugas dan pengendalian pengecualian; 2. ProjectReactor menyediakan jenis mono dan fluks untuk melaksanakan pengaturcaraan responsif, dengan mekanisme tekanan belakang dan pengendali yang kaya; 3. Thread maya mengurangkan kos konvensional, sesuai untuk tugas I/O-intensif, dan lebih ringan dan lebih mudah untuk berkembang daripada benang platform tradisional. Setiap kaedah mempunyai senario yang berkenaan, dan alat yang sesuai harus dipilih mengikut keperluan anda dan model campuran harus dielakkan untuk mengekalkan kesederhanaan

Di Java, enums sesuai untuk mewakili set tetap tetap. Amalan terbaik termasuk: 1. Gunakan enum untuk mewakili keadaan tetap atau pilihan untuk meningkatkan keselamatan jenis dan kebolehbacaan; 2. Tambah sifat dan kaedah untuk meningkatkan fleksibiliti, seperti menentukan bidang, pembina, kaedah penolong, dan lain -lain; 3. Gunakan enummap dan enumset untuk meningkatkan prestasi dan jenis keselamatan kerana mereka lebih cekap berdasarkan tatasusunan; 4. Elakkan penyalahgunaan enum, seperti nilai dinamik, perubahan kerap atau senario logik kompleks, yang harus digantikan dengan kaedah lain. Penggunaan enum yang betul boleh meningkatkan kualiti kod dan mengurangkan kesilapan, tetapi anda perlu memberi perhatian kepada sempadannya yang berkenaan.

Javanio adalah IOAPI baru yang diperkenalkan oleh Java 1.4. 1) bertujuan untuk penampan dan saluran, 2) mengandungi komponen teras penampan, saluran dan pemilih, 3) menyokong mod tidak menyekat, dan 4) mengendalikan sambungan serentak lebih cekap daripada IO tradisional. Kelebihannya dicerminkan dalam: 1) IO yang tidak menyekat mengurangkan overhead thread, 2) Buffer meningkatkan kecekapan penghantaran data, 3) pemilih menyedari multiplexing, dan 4) memori pemetaan memori sehingga membaca dan menulis fail. Nota Apabila menggunakan: 1) Operasi flip/jelas penampan mudah dikelirukan, 2) Data yang tidak lengkap perlu diproses secara manual tanpa menyekat, 3) Pendaftaran pemilih mesti dibatalkan dalam masa, 4) NIO tidak sesuai untuk semua senario.

Mekanisme pemuatan kelas Java dilaksanakan melalui kelas, dan aliran kerja terasnya dibahagikan kepada tiga peringkat: memuatkan, menghubungkan dan memulakan. Semasa fasa pemuatan, kelas muat turun secara dinamik membaca bytecode kelas dan mencipta objek kelas; Pautan termasuk mengesahkan ketepatan kelas, memperuntukkan memori kepada pembolehubah statik, dan rujukan simbol parsing; Inisialisasi melakukan blok kod statik dan tugasan pembolehubah statik. Pemuatan kelas mengamalkan model delegasi induk, dan mengutamakan loader kelas induk untuk mencari kelas, dan cuba bootstrap, lanjutan, dan appliclassloader pada gilirannya untuk memastikan perpustakaan kelas teras selamat dan mengelakkan pemuatan pendua. Pemaju boleh menyesuaikan kelas, seperti UrlClassl

JavaprovidesmultiplesynchronizationToolsforthreadsafety.1.SynchronizedBlockSensensureMutualExclusionByLockingMethodsorspecificcodesections.2.reentrantlockoffersadvancedControl, termasuktrylockandfairnesspolicies.condition

Kunci pengendalian pengecualian Java adalah untuk membezakan antara pengecualian yang diperiksa dan tidak terkawal dan menggunakan percubaan cuba, akhirnya dan pembalakan munasabah. 1. Pengecualian yang diperiksa seperti IOException perlu dipaksa untuk mengendalikan, yang sesuai untuk masalah luaran yang diharapkan; 2. Pengecualian yang tidak terkawal seperti NullPointerException biasanya disebabkan oleh kesilapan logik program dan kesilapan runtime; 3. Apabila menangkap pengecualian, mereka harus khusus dan jelas untuk mengelakkan penangkapan umum pengecualian; 4. Adalah disyorkan untuk menggunakan sumber-sumber cuba untuk menutup sumber secara automatik untuk mengurangkan pembersihan kod manual; 5. Dalam pengendalian pengecualian, maklumat terperinci harus direkodkan dalam kombinasi dengan rangka kerja log untuk memudahkan kemudian

HashMap melaksanakan penyimpanan pasangan nilai utama melalui jadual hash di Java, dan terasnya terletak di lokasi data yang cepat. 1. Mula -mula gunakan kaedah hashcode () kunci untuk menghasilkan nilai hash dan mengubahnya menjadi indeks array melalui operasi bit; 2 Objek yang berbeza boleh menghasilkan nilai hash yang sama, mengakibatkan konflik. Pada masa ini, nod dipasang dalam bentuk senarai yang dipautkan. Selepas JDK8, senarai yang dipautkan terlalu panjang (panjang lalai 8) dan ia akan ditukar kepada pokok merah dan hitam untuk meningkatkan kecekapan; 3. Apabila menggunakan kelas tersuai sebagai kunci, sama () dan kaedah hashcode () mesti ditulis semula; 4. HashMap secara dinamik mengembangkan kapasiti. Apabila bilangan elemen melebihi kapasiti dan multiplies oleh faktor beban (lalai 0.75), mengembangkan dan mengembalikan; 5. hashmap tidak selamat benang, dan concu harus digunakan dalam multithreaded
