Menguasai framework Spring 5, Bagian 2: Spring WebFlux

Spring WebFlux memperkenalkan pengembangan web reaktif ke ekosistem Spring. Artikel ini akan membantu Anda memulai dengan sistem reaktif dan pemrograman reaktif dengan Spring. Pertama, Anda akan mengetahui mengapa sistem reaktif itu penting dan bagaimana penerapannya dalam kerangka kerja Spring 5, lalu Anda akan mendapatkan pengantar langsung untuk membangun layanan reaktif menggunakan Spring WebFlux. Kami akan membangun aplikasi reaktif pertama kami menggunakan anotasi. Saya juga akan menunjukkan kepada Anda cara membuat aplikasi serupa menggunakan fitur fungsional Spring yang lebih baru.

Tutorial musim semi di JavaWorld

Jika Anda baru mengenal framework Spring, saya sarankan untuk memulai dengan salah satu tutorial sebelumnya di seri ini:

  • Apa itu Spring? Pengembangan berbasis komponen untuk Java
  • Menguasai framework Spring 5: Spring MVC

Sistem reaktif dan Spring WebFlux

Istilah reaktif saat ini populer di kalangan pengembang dan manajer TI, tetapi saya memperhatikan beberapa ketidakpastian tentang apa sebenarnya artinya. Untuk memperjelas apa itu sistem reaktif, akan sangat membantu untuk memahami masalah mendasar yang dirancang untuk mereka selesaikan. Di bagian ini kita akan berbicara tentang sistem reaktif secara umum, dan saya akan memperkenalkan API Aliran Reaktif untuk aplikasi Java.

Skalabilitas di Spring MVC

Spring MVC telah mendapatkan tempatnya di antara pilihan teratas untuk membangun aplikasi web dan layanan web Java. Seperti yang kami temukan di Mastering Spring framework 5, Bagian 1, Spring MVC secara mulus mengintegrasikan anotasi ke dalam arsitektur aplikasi berbasis Spring yang tangguh. Hal ini memungkinkan pengembang yang terbiasa dengan Spring untuk dengan cepat membangun aplikasi web yang sangat fungsional dan memuaskan. Namun, skalabilitas merupakan tantangan bagi aplikasi Spring MVC. Itulah masalah yang coba diatasi oleh Spring WebFlux.

Kerangka kerja web pemblokiran vs non-pemblokiran

Dalam aplikasi web tradisional, ketika server web menerima permintaan dari klien, ia menerima permintaan itu dan menempatkannya dalam antrian eksekusi. Sebuah utas di kumpulan utas antrean eksekusi kemudian menerima permintaan, membaca parameter inputnya, dan menghasilkan respons. Dalam prosesnya, jika thread eksekusi perlu memanggil sumber daya pemblokiran - seperti database, sistem file, atau layanan web lain - thread tersebut akan menjalankan permintaan pemblokiran dan menunggu respons. Dalam paradigma ini, utas diblokir secara efektif hingga sumber daya eksternal merespons, yang menyebabkan masalah kinerja dan membatasi skalabilitas. Untuk mengatasi masalah ini, pengembang membuat kumpulan utas berukuran besar, sehingga sementara satu utas diblokir utas lain dapat terus memproses permintaan. Gambar 1 menunjukkan aliran eksekusi untuk aplikasi web tradisional yang memblokir.

Steven Haines

Kerangka kerja web non-pemblokiran seperti NodeJS dan Play mengambil pendekatan yang berbeda. Alih-alih menjalankan permintaan pemblokiran dan menunggunya selesai, mereka menggunakan I / O non-pemblokiran. Dalam paradigma ini, aplikasi menjalankan permintaan, menyediakan kode yang akan dieksekusi ketika respons dikembalikan, dan kemudian mengembalikan utasnya ke server. Ketika sumber daya eksternal mengembalikan respons, kode yang diberikan akan dijalankan. Secara internal, kerangka kerja non-pemblokiran beroperasi menggunakan loop peristiwa. Di dalam loop, kode aplikasi menyediakan callback atau masa depan yang berisi kode untuk dieksekusi ketika loop asinkron selesai.

Secara alami, kerangka kerja non-pemblokiran didorong oleh peristiwa . Ini membutuhkan paradigma pemrograman yang berbeda dan pendekatan baru untuk penalaran tentang bagaimana kode Anda akan dieksekusi. Setelah Anda memikirkannya, pemrograman reaktif dapat menghasilkan aplikasi yang sangat skalabel.

Panggilan balik, janji, dan masa depan

Pada awalnya, JavaScript menangani semua fungsi asinkron melalui callback . Dalam skenario ini, ketika sebuah peristiwa terjadi (seperti ketika respons dari panggilan layanan menjadi tersedia) callback dijalankan. Meskipun callback masih lazim, fungsi asinkron JavaScript baru-baru ini beralih ke promise . Dengan janji, panggilan fungsi segera kembali, mengembalikan janji untuk memberikan hasil di masa mendatang. Daripada janji, Java menerapkan paradigma serupa menggunakan futures . Dalam penggunaan ini, metode mengembalikan masa depan yang akan memiliki nilai di masa mendatang.

Pemrograman reaktif

Anda mungkin pernah mendengar istilah pemrograman reaktif terkait dengan kerangka kerja dan alat pengembangan web, tetapi apa sebenarnya artinya? Istilah yang kita kenal itu berasal dari Manifesto Reaktif, yang mendefinisikan sistem reaktif memiliki empat ciri inti:

  1. Sistem reaktif bersifat responsif , artinya sistem merespons dengan tepat waktu, dalam semua keadaan yang memungkinkan. Mereka fokus pada penyediaan waktu respons yang cepat dan konsisten, menetapkan batas atas yang andal sehingga mereka memberikan kualitas layanan yang konsisten.
  2. Sistem reaktif bersifat ulet , artinya sistem tersebut tetap responsif saat menghadapi kegagalan. Ketahanan dicapai dengan teknik replikasi, penahanan, isolasi, dan pendelegasian. Dengan mengisolasi komponen aplikasi satu sama lain, Anda dapat berisi kegagalan dan melindungi sistem secara keseluruhan.
  3. Sistem reaktif bersifat elastis , artinya sistem tetap responsif di bawah berbagai beban kerja. Ini dicapai dengan menskalakan komponen aplikasi secara elastis untuk memenuhi permintaan saat ini.
  4. Sistem reaktif didorong oleh pesan , artinya sistem tersebut mengandalkan pesan asinkron yang lewat antar komponen. Ini memungkinkan Anda membuat kopling longgar, isolasi, dan transparansi lokasi.

Gambar 2 menunjukkan bagaimana sifat-sifat ini mengalir bersama dalam sistem reaktif.

Steven Haines

Karakteristik sistem reaktif

Sistem reaktif dibangun dengan membuat komponen terisolasi yang berkomunikasi satu sama lain secara asinkron dan dapat menskalakan dengan cepat untuk memenuhi beban saat ini. Komponen masih gagal dalam sistem reaktif, tetapi ada tindakan yang ditentukan untuk dilakukan sebagai akibat dari kegagalan itu, yang membuat sistem secara keseluruhan berfungsi dan responsif.

The Reaktif Manifesto adalah abstrak, tapi aplikasi reaktif biasanya ditandai oleh komponen atau teknik berikut:

  • Aliran data : Aliran adalah urutan peristiwa yang diurutkan dalam waktu, seperti interaksi pengguna, panggilan layanan REST, pesan JMS, dan hasil dari database.
  • Asinkron : Peristiwa aliran data ditangkap secara asinkron dan kode Anda menentukan apa yang harus dilakukan ketika sebuah peristiwa dipancarkan, kapan kesalahan terjadi, dan kapan aliran peristiwa telah selesai.
  • Non-pemblokiran : Saat Anda memproses acara, kode Anda tidak boleh memblokir dan melakukan panggilan sinkron; sebagai gantinya, ia harus membuat panggilan asinkron dan merespons sebagai hasil dari panggilan tersebut dikembalikan.
  • Tekanan balik: Komponen mengontrol jumlah kejadian dan seberapa sering mereka dipancarkan. Dalam istilah reaktif, komponen Anda disebut sebagai pelanggan dan acara dipancarkan oleh penerbit . Ini penting karena pelanggan mengontrol berapa banyak data yang diterimanya dan dengan demikian tidak akan membebani dirinya sendiri.
  • Pesan kegagalan : Sebagai ganti komponen yang memberikan pengecualian, kegagalan dikirim sebagai pesan ke fungsi penangan. Sedangkan melempar pengecualian memecah aliran, mendefinisikan fungsi untuk menangani kegagalan saat terjadi tidak.

API Aliran Reaktif

Reactive Streams API baru dibuat oleh teknisi dari Netflix, Pivotal, Lightbend, RedHat, Twitter, Oracle, dan lainnya. Dipublikasikan pada tahun 2015, Reactive Streams API sekarang menjadi bagian dari Java 9. Ini mendefinisikan empat antarmuka:

  • Penerbit : Memancarkan urutan acara ke pelanggan.
  • Pelanggan : Menerima dan memproses acara yang dikeluarkan oleh Penerbit.
  • Langganan : Mendefinisikan hubungan satu-ke-satu antara Penerbit dan Pelanggan.
  • Prosesor : Merupakan tahap pemrosesan yang terdiri dari Pelanggan dan Penerbit dan mematuhi kontrak keduanya.

Gambar 3 menunjukkan hubungan antara Penerbit, Pelanggan, dan Langganan.

Steven Haines

Intinya, Pelanggan membuat Langganan ke Penerbit dan, ketika Penerbit memiliki data yang tersedia, ia mengirimkan acara ke Pelanggan dengan aliran elemen. Perhatikan bahwa Pelanggan mengelola tekanan baliknya di dalam Langganan ke Penerbitnya.

Sekarang setelah Anda mengetahui sedikit tentang sistem reaktif dan API Aliran Reaktif, mari kita alihkan perhatian kita ke alat yang digunakan Spring untuk mengimplementasikan sistem reaktif: Spring WebFlux dan pustaka Reactor.

Reaktor Proyek

Project Reactor adalah kerangka kerja pihak ketiga berdasarkan Spesifikasi Reactive Streams Java, yang digunakan untuk membangun aplikasi web non-pemblokiran. Project Reactor menyediakan dua penerbit yang banyak digunakan di Spring WebFlux:

  • Mono : Mengembalikan 0 atau 1 elemen.
  • Fluks : Mengembalikan 0 elemen atau lebih. Flux bisa tidak terbatas, artinya Flux dapat terus memancarkan elemen selamanya, atau dapat mengembalikan urutan elemen dan kemudian mengirimkan pemberitahuan penyelesaian ketika telah mengembalikan semua elemennya.

Mono dan fluks secara konseptual mirip dengan futures, tetapi lebih kuat. Saat Anda menjalankan fungsi yang mengembalikan mono atau fluks, fungsi tersebut akan segera kembali. Hasil panggilan fungsi akan dikirimkan kepada Anda melalui mono atau fluks saat tersedia.

Di Spring WebFlux, Anda akan memanggil pustaka reaktif yang mengembalikan mono dan fluks dan pengontrol Anda akan mengembalikan mono dan fluks. Karena ini segera kembali, pengontrol Anda akan secara efektif melepaskan utas mereka dan memungkinkan Reaktor menangani respons secara asinkron. Penting untuk diperhatikan bahwa hanya dengan menggunakan pustaka reaktif layanan WebFlux Anda dapat tetap reaktif. Jika Anda menggunakan pustaka non-reaktif, seperti panggilan JDBC, kode Anda akan memblokir dan menunggu panggilan tersebut selesai sebelum kembali.

Pemrograman reaktif dengan MongoDB

Saat ini, tidak banyak pustaka database reaktif, jadi Anda mungkin bertanya-tanya apakah praktis untuk menulis layanan reaktif. Kabar baiknya adalah MongoDB memiliki dukungan reaktif dan ada beberapa driver database reaktif pihak ketiga untuk MySQL dan Postgres. Untuk semua kasus penggunaan lainnya, WebFlux menyediakan mekanisme untuk menjalankan panggilan JDBC secara reaktif, meskipun menggunakan kumpulan thread sekunder yang memblokir panggilan JDBC.

Mulailah dengan Spring WebFlux

Untuk contoh cara kami yang pertama, kami akan membuat layanan buku sederhana yang menyimpan buku ke dan dari MongoDB dengan cara yang reaktif.

Mulailah dengan menavigasi ke beranda Spring Initializr, di mana Anda akan memilih proyek Maven dengan Java dan memilih rilis terbaru dari Spring Boot (2.0.3 pada saat penulisan ini). Beri proyek Anda nama grup, seperti "com.javaworld.webflux", dan nama artefak, seperti "layanan buku". Perluas tautan Beralih ke versi lengkap untuk menampilkan daftar lengkap dependensi. Pilih dependensi berikut untuk aplikasi contoh:

  • Web -> Web Reaktif : Dependensi ini mencakup Spring WebFlux.
  • NoSQL -> MongoDB Reaktif : Dependensi ini mencakup driver reaktif untuk MongoDB.
  • NoSQL -> Embedded MongoDB : Dependensi ini memungkinkan kita menjalankan versi MongoDB yang disematkan, jadi tidak perlu menginstal instance terpisah. Biasanya ini digunakan untuk pengujian, tetapi kami akan memasukkannya ke dalam kode rilis kami untuk menghindari pemasangan MongoDB.
  • Core -> Lombok : Menggunakan Lombok adalah opsional karena Anda tidak memerlukannya untuk membuat aplikasi Spring WebFlux. Keuntungan menggunakan Project Lombok adalah bahwa hal itu memungkinkan Anda untuk menambahkan penjelasan ke kelas yang secara otomatis akan menghasilkan getter dan setter, konstruktor, hashCode(), equals(), dan banyak lagi.

Setelah selesai, Anda akan melihat sesuatu yang mirip dengan Gambar 4.

Steven Haines

Menekan Hasilkan Proyek akan memicu pengunduhan file zip yang berisi kode sumber proyek Anda. Buka zip file yang diunduh dan buka di IDE favorit Anda. Jika Anda menggunakan IntelliJ, pilih File lalu Buka , dan navigasikan ke direktori tempat file zip yang diunduh telah didekompresi.

Anda akan menemukan bahwa Spring Initializr telah menghasilkan dua file penting:

  1. pom.xmlFile Maven , yang menyertakan semua dependensi yang diperlukan untuk aplikasi.
  2. BookserviceApplication.java, yang merupakan kelas starter Spring Boot untuk aplikasi tersebut.

Kode 1 menunjukkan isi dari file pom.xml yang dihasilkan.