Pengenalan Projek Reactor Bus

1. Gambaran keseluruhan

Dalam artikel ringkas ini, kami akan memperkenalkan reaktor-bus dengan menyusun senario kehidupan sebenar untuk aplikasi yang berdasarkan aktiviti dan reaktif.

2. Asas Reaktor Projek

2.1. Mengapa Reaktor?

Aplikasi moden perlu menangani sejumlah besar permintaan serentak dan memproses sejumlah besar data. Standard, kod penyekat tidak lagi mencukupi untuk memenuhi keperluan ini.

Corak reka bentuk reaktif adalah pendekatan seni bina berasaskan acara untuk pengendalian asinkron dari sejumlah besar permintaan serentak yang datang dari pengendali perkhidmatan tunggal atau berbilang.

Project Reactor berdasarkan corak ini dan mempunyai matlamat yang jelas dan bercita-cita tinggi untuk membina aplikasi yang tidak menyekat dan reaktif di JVM .

2.2. Contoh Senario

Sebelum kita memulakan, berikut adalah beberapa senario menarik di mana memanfaatkan gaya seni bina reaktif akan masuk akal, hanya untuk mendapatkan idea di mana kita dapat menerapkannya:

  • Perkhidmatan pemberitahuan untuk platform membeli-belah dalam talian yang besar seperti Amazon
  • Perkhidmatan pemprosesan transaksi yang besar untuk sektor perbankan
  • Perniagaan perdagangan saham di mana harga saham berubah serentak

3. Pergantungan Maven

Mari mula menggunakan Project Reactor Bus dengan menambahkan kebergantungan berikut ke dalam pom.xml kami :

 io.projectreactor reactor-bus 2.0.8.RELEASE 

Kami boleh memeriksa versi reaktor-bas terkini di Maven Central.

4. Membangun Aplikasi Demo

Untuk lebih memahami faedah pendekatan berasaskan reaktor, mari kita lihat contoh praktikalnya.

Kami akan membina aplikasi mudah yang bertanggungjawab untuk menghantar pemberitahuan kepada pengguna platform membeli-belah dalam talian. Sebagai contoh, jika pengguna membuat pesanan baru, aplikasi akan menghantar pengesahan pesanan melalui e-mel atau SMS.

Pelaksanaan sinkron biasa biasanya akan dibatasi oleh throughput perkhidmatan e-mel atau SMS. Oleh itu, lonjakan lalu lintas, seperti cuti pada amnya akan menimbulkan masalah.

Dengan pendekatan reaktif, kita dapat merancang sistem kita agar lebih fleksibel dan dapat menyesuaikan diri lebih baik dengan kegagalan atau batas waktu yang mungkin berlaku pada sistem luaran, seperti pelayan gerbang.

Mari lihat aplikasi - bermula dengan aspek yang lebih tradisional dan beralih ke konstruk yang lebih reaktif.

4.1. POJO ringkas

Pertama, mari buat kelas POJO untuk mewakili data pemberitahuan:

public class NotificationData { private long id; private String name; private String email; private String mobile; // getter and setter methods }

4.2. Lapisan Perkhidmatan

Sekarang mari kita tentukan lapisan perkhidmatan yang mudah:

public interface NotificationService { void initiateNotification(NotificationData notificationData) throws InterruptedException; }

Dan pelaksanaannya, mensimulasikan operasi jangka panjang:

@Service public class NotificationServiceimpl implements NotificationService { @Override public void initiateNotification(NotificationData notificationData) throws InterruptedException { System.out.println("Notification service started for " + "Notification ID: " + notificationData.getId()); Thread.sleep(5000); System.out.println("Notification service ended for " + "Notification ID: " + notificationData.getId()); } }

Perhatikan bahawa untuk menggambarkan senario kehidupan sebenar mesej yang hantar melalui SMS atau e-mel gateway, kami sengaja memperkenalkan lima saat kelewatan dalam initiateNotification kaedah dengan Thread.sleep (5000).

Akibatnya, apabila utas menyentuh perkhidmatan, ia akan disekat selama lima saat.

4.3. Pengguna

Sekarang mari kita melihat aspek aplikasi yang lebih reaktif dan menerapkan pengguna - yang kemudian akan kita petak ke bas acara reaktor:

@Service public class NotificationConsumer implements Consumer
    
      { @Autowired private NotificationService notificationService; @Override public void accept(Event notificationDataEvent) { NotificationData notificationData = notificationDataEvent.getData(); try { notificationService.initiateNotification(notificationData); } catch (InterruptedException e) { // ignore } } }
    

Seperti yang kita lihat, pengguna yang kita buat menggunakan antara muka Pengguna . Logik utama terdapat dalam kaedah terima .

Ini adalah pendekatan serupa yang dapat kita temui dalam pelaksanaan pendengar Spring khas.

4.4. Pengawal

Akhirnya, setelah kita dapat menghabiskan acara, mari kita menjayakannya.

Kami akan melakukannya dalam pengawal mudah:

@Controller public class NotificationController { @Autowired private EventBus eventBus; @GetMapping("/startNotification/{param}") public void startNotification(@PathVariable Integer param) { for (int i = 0; i < param; i++) { NotificationData data = new NotificationData(); data.setId(i); eventBus.notify("notificationConsumer", Event.wrap(data)); System.out.println( "Notification " + i + ": notification task submitted successfully"); } } }

Ini cukup jelas - kami memancarkan acara melalui EventBus di sini.

Sebagai contoh, jika pelanggan memukul URL dengan nilai param sepuluh, maka sepuluh acara akan dihantar melalui bus acara.

4.5. Konfigurasi Java

Mari sekarang satukan semuanya dan buat aplikasi Spring Boot yang ringkas.

Pertama, kita perlu mengkonfigurasi kacang EventBus dan Environment :

@Configuration public class Config { @Bean public Environment env() { return Environment.initializeIfEmpty().assignErrorJournal(); } @Bean public EventBus createEventBus(Environment env) { return EventBus.create(env, Environment.THREAD_POOL); } }

Dalam kes kami, kami menyediakan EventBus dengan kumpulan utas lalai yang tersedia di persekitaran .

Sebagai alternatif, kita dapat menggunakan contoh Dispatcher yang disesuaikan :

EventBus evBus = EventBus.create( env, Environment.newDispatcher( REACTOR_CAPACITY,REACTOR_CONSUMERS_COUNT, DispatcherType.THREAD_POOL_EXECUTOR));

Sekarang, kami bersedia membuat kod aplikasi utama:

import static reactor.bus.selector.Selectors.$; @SpringBootApplication public class NotificationApplication implements CommandLineRunner { @Autowired private EventBus eventBus; @Autowired private NotificationConsumer notificationConsumer; @Override public void run(String... args) throws Exception { eventBus.on($("notificationConsumer"), notificationConsumer); } public static void main(String[] args) { SpringApplication.run(NotificationApplication.class, args); } }

Dalam kaedah jalankan kami mendaftarkan notificationConsumer yang akan dipicu ketika pemberitahuan sesuai dengan pemilih tertentu .

Perhatikan bagaimana kita menggunakan import statik atribut $ untuk membuat objek Pemilih .

5. Uji Aplikasi

Mari sekarang buat ujian untuk melihat Aplikasi Pemberitahuan kami dalam tindakan:

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class NotificationApplicationIntegrationTest { @LocalServerPort private int port; @Test public void givenAppStarted_whenNotificationTasksSubmitted_thenProcessed() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getForObject("//localhost:" + port + "/startNotification/10", String.class); } }

Seperti yang dapat kita lihat, segera setelah permintaan itu dilaksanakan, kesemua sepuluh tugas tersebut diserahkan serta-merta tanpa membuat penyekat . Dan setelah dihantar, acara pemberitahuan diproses secara selari.

Notification 0: notification task submitted successfully Notification 1: notification task submitted successfully Notification 2: notification task submitted successfully Notification 3: notification task submitted successfully Notification 4: notification task submitted successfully Notification 5: notification task submitted successfully Notification 6: notification task submitted successfully Notification 7: notification task submitted successfully Notification 8: notification task submitted successfully Notification 9: notification task submitted successfully Notification service started for Notification ID: 1 Notification service started for Notification ID: 2 Notification service started for Notification ID: 3 Notification service started for Notification ID: 0 Notification service ended for Notification ID: 1 Notification service ended for Notification ID: 0 Notification service started for Notification ID: 4 Notification service ended for Notification ID: 3 Notification service ended for Notification ID: 2 Notification service started for Notification ID: 6 Notification service started for Notification ID: 5 Notification service started for Notification ID: 7 Notification service ended for Notification ID: 4 Notification service started for Notification ID: 8 Notification service ended for Notification ID: 6 Notification service ended for Notification ID: 5 Notification service started for Notification ID: 9 Notification service ended for Notification ID: 7 Notification service ended for Notification ID: 8 Notification service ended for Notification ID: 9

Penting untuk diingat bahawa dalam senario kita tidak perlu memproses peristiwa ini dalam urutan tertentu.

6. Kesimpulannya

Dalam tutorial ringkas ini, kami telah membuat aplikasi berdasarkan acara sederhana . Kami juga telah melihat bagaimana untuk mula menulis kod yang lebih reaktif dan tidak menyekat.

Walau bagaimanapun, senario ini hanya menggaru permukaan subjek dan mewakili asas yang baik untuk mula bereksperimen dengan paradigma reaktif .

Seperti biasa, kod sumber tersedia di GitHub.