
Pendahuluan
Pada artikel sebelumnya, kami menjelaskan secara singkat proses menciptakan microservice pada kerangka kerja JVM modern, serta perbandingannya. Artikel ini akan dibahas secara lebih terperinci dalam Quarkus yang baru-baru ini dirilis dengan contoh membuat layanan-mikro menggunakan teknologi yang disebutkan dan sesuai dengan persyaratan yang ditentukan dalam artikel utama. Aplikasi yang dihasilkan akan menjadi bagian dari arsitektur microservice berikut:

Kode sumber proyek, seperti biasa, tersedia di GitHub .
Sebelum mulai bekerja dengan suatu proyek, berikut ini harus diinstal:
Buat proyek baru
Untuk menghasilkan proyek baru, gunakan web starter atau Maven (untuk membuat proyek Maven atau proyek Gradle ). Perlu dicatat bahwa kerangka mendukung bahasa Java, Kotlin dan Scala.
Kecanduan
Dalam proyek ini, Gradle Kotlin DSL digunakan sebagai sistem pembangunan. Skrip build harus berisi:
plugin
Listing 1. build.gradle.kts
plugins { kotlin("jvm") kotlin("plugin.allopen") id("io.quarkus") }
Resolusi versi plugin dilakukan di settings.gradle.kts
.
kecanduan
Listing 2. build.gradle.kts
dependencies { ... implementation(enforcedPlatform("io.quarkus:quarkus-bom:$quarkusVersion")) implementation("io.quarkus:quarkus-resteasy-jackson") implementation("io.quarkus:quarkus-rest-client") implementation("io.quarkus:quarkus-kotlin") implementation("io.quarkus:quarkus-config-yaml") testImplementation("io.quarkus:quarkus-junit5") ... }
Informasi tentang mengimpor Maven BOM tersedia di dokumentasi Gradle .
Anda juga perlu membuat beberapa kelas Kotlin open
(mereka final
secara default; informasi lebih lanjut tentang mengkonfigurasi Gradle dalam panduan Quarkus Kotlin :
Listing 3. build.gradle.kts
allOpen { annotation("javax.enterprise.context.ApplicationScoped") }
Konfigurasi
Kerangka kerja ini mendukung konfigurasi menggunakan properti dan file YAML
(lebih lanjut dalam panduan konfigurasi Quarkus ). File konfigurasi terletak di folder resources
dan terlihat seperti ini:
Listing 4. application.yaml
quarkus: http: host: localhost port: 8084 application-info: name: quarkus-service framework: name: Quarkus release-year: 2019
Dalam fragmen kode ini, parameter standar dan khusus pada perangkat mikro dikonfigurasikan. Yang terakhir dapat dibaca seperti ini:
Listing 5. Membaca parameter aplikasi khusus ( kode sumber )
import io.quarkus.arc.config.ConfigProperties @ConfigProperties(prefix = "application-info") class ApplicationInfoProperties { lateinit var name: String lateinit var framework: FrameworkConfiguration class FrameworkConfiguration { lateinit var name: String lateinit var releaseYear: String } }
Tempat sampah
Sebelum Anda mulai bekerja dengan kode, perlu dicatat bahwa dalam kode sumber aplikasi Quarkus tidak ada metode utama (walaupun mungkin muncul ).
@ConfigProperties
kacang @ConfigProperties
dari daftar sebelumnya ke kacang lain dilakukan menggunakan anotasi @Inject
:
Listing 6. Menerapkan kacang @ConfigProperties
( sumber )
@ApplicationScoped class ApplicationInfoService( @Inject private val applicationInfoProperties: ApplicationInfoProperties, @Inject private val serviceClient: ServiceClient ) { ... }
Kacang ApplicationInfoService
dijelaskan oleh @ApplicationScoped
, pada gilirannya, dilaksanakan sebagai berikut:
Daftar 7. Menyebarkan kacang @ApplicationScoped
( sumber )
class ApplicationInfoResource( @Inject private val applicationInfoService: ApplicationInfoService )
Informasi lebih lanjut tentang Konteks dan Injeksi Ketergantungan dalam panduan Quarkus CDI .
Kontroler SISA
Tidak ada yang tidak biasa dalam kontroler REST untuk mereka yang bekerja dengan Spring Framework atau Java EE:
Listing 8. Kontroler SISA ( sumber )
@Path("/application-info") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) class ApplicationInfoResource( @Inject private val applicationInfoService: ApplicationInfoService ) { @GET fun get(@QueryParam("request-to") requestTo: String?): Response = Response.ok(applicationInfoService.get(requestTo)).build() @GET @Path("/logo") @Produces("image/png") fun logo(): Response = Response.ok(applicationInfoService.getLogo()).build() }
REST client
Untuk bekerja dalam arsitektur microservice Quarkus, sebuah layanan harus dapat memenuhi permintaan untuk layanan lain. Karena semua layanan memiliki API yang sama, masuk akal untuk membuat antarmuka tunggal untuk kode umum dan sekelompok klien REST yang mewarisi itu:
Listing 9. REST klien ( kode sumber )
@ApplicationScoped @Path("/") interface ExternalServiceClient { @GET @Path("/application-info") @Produces("application/json") fun getApplicationInfo(): ApplicationInfo } @RegisterRestClient(baseUri = "http://helidon-service") interface HelidonServiceClient : ExternalServiceClient @RegisterRestClient(baseUri = "http://ktor-service") interface KtorServiceClient : ExternalServiceClient @RegisterRestClient(baseUri = "http://micronaut-service") interface MicronautServiceClient : ExternalServiceClient @RegisterRestClient(baseUri = "http://quarkus-service") interface QuarkusServiceClient : ExternalServiceClient @RegisterRestClient(baseUri = "http://spring-boot-service") interface SpringBootServiceClient : ExternalServiceClient
Seperti yang Anda lihat, membuat klien REST untuk layanan lain hanya membuat antarmuka dengan anotasi JAX-RS dan MicroProfile yang sesuai.
Penemuan layanan
Seperti yang Anda lihat di bagian sebelumnya, nilai parameter baseUri
adalah nama-nama layanan. Namun sejauh ini, Quarkus tidak memiliki dukungan bawaan untuk Layanan Penemuan ( Eureka ) atau tidak berfungsi ( Konsul ), karena kerangka kerjanya terutama ditujukan untuk bekerja di lingkungan cloud. Oleh karena itu, pola Penemuan Layanan diimplementasikan menggunakan Klien Konsul untuk perpustakaan Java .
Klien untuk Konsul mencakup dua metode, register
dan getServiceInstance
(menggunakan algoritma Round-robin):
Listing 10. Klien ke Konsul ( sumber )
@ApplicationScoped class ConsulClient( @ConfigProperty(name = "application-info.name") private val serviceName: String, @ConfigProperty(name = "quarkus.http.port") private val port: Int ) { private val consulUrl = "http://localhost:8500" private val consulClient by lazy { Consul.builder().withUrl(consulUrl).build() } private var serviceInstanceIndex: Int = 0 fun register() { consulClient.agentClient().register(createConsulRegistration()) } fun getServiceInstance(serviceName: String): Service { val serviceInstances = consulClient.healthClient().getHealthyServiceInstances(serviceName).response val selectedInstance = serviceInstances[serviceInstanceIndex] serviceInstanceIndex = (serviceInstanceIndex + 1) % serviceInstances.size return selectedInstance.service } private fun createConsulRegistration() = ImmutableRegistration.builder() .id("$serviceName-$port") .name(serviceName) .address("localhost") .port(port) .build() }
Pertama, Anda perlu mendaftarkan aplikasi:
Listing 11. Mendaftar ke Konsul ( sumber )
@ApplicationScoped class ConsulRegistrationBean( @Inject private val consulClient: ConsulClient ) { fun onStart(@Observes event: StartupEvent) { consulClient.register() } }
Selanjutnya, Anda perlu mengonversi nama layanan menjadi lokasi nyata. Untuk melakukan ini, gunakan kelas yang memperluas ClientRequestFilter
dan @Provider
beranotasi:
Listing 12. Filter untuk bekerja dengan Service Discovery ( sumber )
@Provider @ApplicationScoped class ConsulFilter( @Inject private val consulClient: ConsulClient ) : ClientRequestFilter { override fun filter(requestContext: ClientRequestContext) { val serviceName = requestContext.uri.host val serviceInstance = consulClient.getServiceInstance(serviceName) val newUri: URI = URIBuilder(URI.create(requestContext.uri.toString())) .setHost(serviceInstance.address) .setPort(serviceInstance.port) .build() requestContext.uri = newUri } }
Filter hanya menggantikan URI objek requestContext
dengan lokasi layanan yang diterima dari klien ke Konsul.
Pengujian
Tes untuk dua metode API diimplementasikan menggunakan perpustakaan REST Assured:
Listing 13. Tes ( sumber )
@QuarkusTest class QuarkusServiceApplicationTest { @Test fun testGet() { given() .`when`().get("/application-info") .then() .statusCode(200) .contentType(ContentType.JSON) .body("name") { `is`("quarkus-service") } .body("framework.name") { `is`("Quarkus") } .body("framework.releaseYear") { `is`(2019) } } @Test fun testGetLogo() { given() .`when`().get("/application-info/logo") .then() .statusCode(200) .contentType("image/png") .body(`is`(notNullValue())) } }
Selama pengujian, tidak perlu mendaftar aplikasi dengan Konsul, oleh karena itu, dalam kode sumber proyek di sebelah pengujian adalah ConsulClientMock
, yang memperluas ConsulClient
:
Listing 14. Mock for ConsulClient
( sumber )
@Mock @ApplicationScoped class ConsulClientMock : ConsulClient("", 0) {
Majelis
Selama tugas build
Gradle, tugas quarkusBuild
. Secara default, ini menghasilkan JAR pelari dan folder lib
mana dependensi berada. Untuk membuat uber-JAR, tugas quarkusBuild
dikonfigurasi sebagai berikut:
Listing 15. Mengkonfigurasi generasi uber-JAR ( sumber )
tasks { withType<QuarkusBuild> { isUberJar = true } }
Untuk membangun, jalankan ./gradlew clean build
di akar proyek.
Luncurkan
Sebelum memulai microservice, Anda harus memulai Konsul (dijelaskan dalam artikel utama ).
Microservice dapat mulai menggunakan:
- Tugas
quarkusDev
Jalankan pada akar proyek:
./gradlew :quarkus-service:quarkusDev
atau jalankan tugas di IDE - uber-jar
Jalankan pada akar proyek:
java -jar quarkus-service/build/quarkus-service-1.0.0-runner.jar
Sekarang Anda dapat menggunakan REST API, misalnya, jalankan kueri berikut:
GET http://localhost:8084/application-info
Hasilnya adalah:
Listing 16. Hasil dari panggilan API
{ "name": "quarkus-service", "framework": { "name": "Quarkus", "releaseYear": 2019 }, "requestedService": null }
Kompatibilitas Musim Semi
Kerangka kerja ini menyediakan kompatibilitas dengan beberapa teknologi Pegas: DI , Web , Keamanan , Data JPA .
Kesimpulan
Artikel itu meneliti contoh membuat layanan REST sederhana di Quarkus menggunakan Kotlin dan Gradle. Pada artikel utama, Anda dapat melihat bahwa aplikasi yang dihasilkan memiliki parameter yang sebanding dengan aplikasi pada kerangka kerja JVM modern lainnya. Dengan demikian, Quarkus memiliki pesaing serius, seperti Helidon MicroProfile, Micronaut dan Spring Boot (jika kita berbicara tentang kerangka kerja fullstack). Oleh karena itu, saya pikir kami sedang menunggu perkembangan acara yang menarik yang akan bermanfaat bagi seluruh ekosistem Jawa.
Tautan yang bermanfaat
PS Terima kasih vladimirsitnikov untuk bantuan dalam mempersiapkan artikel.