ΠΠ΄ΡΠ°Π²Π΅ΠΉΡΠ΅ Π½Π° Π²ΡΠΈΡΠΊΠΈ! ΠΡΠΎ Π³ΠΎ β Π½Π°ΡΠΈΡΡ Π·Π°ΠΊΠ»ΡΡΠΈΡΠ΅Π»Π΅Π½ ΠΏΠΎΡΡ ΠΎΡ ΡΠ΅ΡΠΈΡΡΠ° Π·Π° Quarkus! (ΠΠ΅ΠΆΠ΄Ρ Π΄ΡΡΠ³ΠΎΡΠΎ, Π²ΠΈΠΆΡΠ΅ ΡΠ΅Π±ΠΈΠ½Π°ΡΠ° Π½ΠΈ . Π©Π΅ ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΠ°ΠΊ Π΄Π° Π·Π°ΠΏΠΎΡΠ½Π΅ΡΠ΅ Β«ΠΎΡ Π½ΡΠ»Π°Β» ΠΈΠ»ΠΈ Π΄Π° ΠΏΡΠ΅Π½Π΅ΡΠ΅ΡΠ΅ Π³ΠΎΡΠΎΠ²ΠΈ ΡΠ΅ΡΠ΅Π½ΠΈΡ)

Π Π² ΡΠΎΠ·ΠΈ ΠΏΠΎΡΡ ΡΠ΅ ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΈΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ, Ρ ΠΊΠΎΠΈΡΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π΅Π½ΠΎ Π΄Π° ΠΎΡΠ΅Π½ΠΈΡΠ΅ ΠΏΠΎΠ΄ΠΎΠ±ΡΠ΅Π½ΠΈΡΡΠ°, ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈ Π² ΡΠ΅Π·ΡΠ»ΡΠ°Ρ Π½Π° ΠΌΠΎΠ΄Π΅ΡΠ½ΠΈΠ·Π°ΡΠΈΡΡΠ° Π½Π° Java ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ.
ΠΠ°ΠΏΠΎΡΠ²Π°ΠΉΠΊΠΈ ΠΎΡ Π²Π΅ΡΡΠΈΡ 0.17.0, ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° Advanced Message Queuing Protocol (), ΠΊΠΎΠΉΡΠΎ Π΅ ΠΎΡΠ²ΠΎΡΠ΅Π½ ΡΡΠ°Π½Π΄Π°ΡΡ Π·Π° ΠΏΡΠ΅Π΄Π°Π²Π°Π½Π΅ Π½Π° Π±ΠΈΠ·Π½Π΅Ρ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΎΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΠΈ.
Π΅ ΡΡΠ»ΡΠ³Π°, ΠΈΠ·Π³ΡΠ°Π΄Π΅Π½Π° Π½Π° Π±Π°Π·Π°ΡΠ° Π½Π° ΠΎΡΠ²ΠΎΡΠ΅Π½ ΠΏΡΠΎΠ΅ΠΊΡ ΠΈ ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ° ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΡΠΌ Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π½Π° Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ°ΡΠ° . ΠΠΎΠ΄ΡΠΎΠ±Π½ΠΎΡΡΠΈ Π·Π° ΡΠΎΠ²Π° ΠΊΠ°ΠΊ Π΅ ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΈΡΠ°Π½, Π²ΠΈΠΆΡΠ΅ . ΠΠ½Π΅Ρ ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΠ°ΠΊ Π΄Π° ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ°ΡΠ΅ AMQ Online ΠΈ Quarkus, Π·Π° Π΄Π° ΠΈΠ·Π³ΡΠ°Π΄ΠΈΡΠ΅ ΡΡΠ²ΡΠ΅ΠΌΠ΅Π½Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π½Π° Π±Π°Π·Π°ΡΠ° Π½Π° OpenShift, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ Π΄Π²Π΅ Π½ΠΎΠ²ΠΈ ΡΠ΅Ρ Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ, ΡΠ²ΡΡΠ·Π°Π½ΠΈ Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°ΡΠ° Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ.
ΠΡΠ΅Π΄ΠΏΠΎΠ»Π°Π³Π° ΡΠ΅, ΡΠ΅ Π²Π΅ΡΠ΅ ΡΡΠ΅ ΡΠ°Π·ΠΏΠΎΠ»ΠΎΠΆΠΈΠ»ΠΈ AMQ Online Π½Π° ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ°ΡΠ° OpenShift (Π°ΠΊΠΎ Π½Π΅, Π²ΠΈΠΆΡΠ΅ ).
ΠΡΡΠ²ΠΎ ΡΠ΅ ΡΡΠ·Π΄Π°Π΄Π΅ΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Quarkus, ΠΊΠΎΠ΅ΡΠΎ ΡΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ²Π° ΠΏΡΠΎΡΡΠ° ΡΠΈΡΡΠ΅ΠΌΠ° Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ Ρ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ΡΠ΅Π°ΠΊΡΠΈΠ²Π΅Π½ ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ. Π’ΠΎΠ²Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡΠ΅ Π²ΠΊΠ»ΡΡΠ²Π° Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ, ΠΊΠΎΠΉΡΠΎ ΠΈΠ·ΠΏΡΠ°ΡΠ° ΠΏΠΎΡΡΡΠΊΠΈ Π² ΠΎΠΏΠ°ΡΠΊΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Ρ ΡΠΈΠΊΡΠΈΡΠ°Π½ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π», ΠΊΠ°ΠΊΡΠΎ ΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ²Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΎΡ ΠΎΠΏΠ°ΡΠΊΠ°ΡΠ° ΠΈ ΡΠ΅ Π³Π΅Π½Π΅ΡΠΈΡΠ° ΠΏΠΎΡΠ²ΡΡΠΆΠ΄Π΅Π½ΠΈΡ, Π½Π°Π»ΠΈΡΠ½ΠΈ Π·Π° ΠΏΡΠ΅Π³Π»Π΅Π΄ Π² Π±ΡΠ°ΡΠ·ΡΡΠ°.
Π‘Π»Π΅Π΄ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ ΠΊΠ°ΠΊ Π΄Π° Π²Π½Π΅Π΄ΡΠΈΡΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΈ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ AMQ Online, Π·Π° Π΄Π° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠ°ΠΌΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈΡΠ΅ ΡΠ΅ΡΡΡΡΠΈ Π² ΡΠ°Π·ΠΈ ΡΠΈΡΡΠ΅ΠΌΠ°.
ΠΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Quarkus
ΠΠ°ΡΠ΅ΡΠΎ Quarkus ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡΠ°Π±ΠΎΡΠΈ Π½Π° OpenShift ΠΈ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ²Π° ΠΌΠΎΠ΄ΠΈΡΠΈΡΠΈΡΠ°Π½Π° Π²Π΅ΡΡΠΈΡ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° . ΠΡΠ»Π½ΠΈΡΡ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠ°ΡΠ° ΡΠ°ΡΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π½Π°ΠΌΠ΅ΡΠΈΡΠ΅ .
ΠΠ΅Π½Π΅ΡΠ°ΡΠΎΡ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ
ΠΠ΅Π½Π΅ΡΠ°ΡΠΎΡΡΡ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ Π½Π° Π²ΡΠ΅ΠΊΠΈ 5 ΡΠ΅ΠΊΡΠ½Π΄ΠΈ ΠΏΡΠΎΡΡΠΎ ΠΈΠ·ΠΏΡΠ°ΡΠ° Π½Π°ΡΠ°ΡΡΠ²Π°ΡΠΈ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΈ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ Π½Π° Π°Π΄ΡΠ΅ΡΠ° "orders".
@ApplicationScoped
public class OrderGenerator {
private int orderId = 1;
@Outgoing("orders")
public Flowable generate() {
return Flowable.interval(5, TimeUnit.SECONDS)
.map(tick -> orderId++);
}
}
ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ
ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΡΡ Π½Π° ΠΏΠΎΡΡΡΠΊΠΈ Π΅ ΠΎΡΠ΅ ΠΏΠΎ-ΠΏΡΠΎΡΡ, ΡΠΎΠΉ ΠΏΡΠΎΡΡΠΎ Π²ΡΡΡΠ° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ Π½Π° ΠΏΠΎΡΠ²ΡΡΠΆΠ΄Π΅Π½ΠΈΠ΅ Π½Π° Π°Π΄ΡΠ΅Ρ "confirmations".
@ApplicationScoped
public class OrderProcessor {
@Incoming("orders")
@Outgoing("confirmations")
public Integer process(Integer order) {
// ΠΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡΡ Π½Π° ΠΏΠΎΡΠ²ΡΡΠΆΠ΄Π΅Π½ΠΈΠ΅ΡΠΎ Π΅ ΡΠ°Π²Π΅Π½ Π½Π° ΡΠ΄Π²ΠΎΠ΅Π½ΠΈΡ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ Π½Π° ΠΏΠΎΡΡΡΠΊΠ°ΡΠ° <img draggable="false" class="emoji" alt=":-)" src="https://s.w.org/images/core/emoji/11.2.0/svg/1f642.svg">
return order * 2;
}
}
Π Π΅ΡΡΡΡΠΈ Π·Π° ΠΏΠΎΡΠ²ΡΡΠ΄Π΅Π½ΠΈΠ΅
Π Π΅ΡΡΡΡ Π·Π° ΠΏΠΎΡΠ²ΡΡΠΆΠ΄Π΅Π½ΠΈΠ΅ Π΅ HTTP ΠΊΡΠ°ΠΉΠ½Π° ΡΠΎΡΠΊΠ° Π·Π° ΡΠΏΠΈΡΡΠΊΠ° Π½Π° Π³Π΅Π½Π΅ΡΠΈΡΠ°Π½ΠΈΡΠ΅ ΠΎΡ Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΡΠ²ΡΡΠΆΠ΄Π΅Π½ΠΈΡ.
@Path("/confirmations")
public class ConfirmationResource {
@Inject
@Stream("confirmations") Publisher orders;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
@GET
@Path("/stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
public Publisher stream() {
return orders;
}
}
ΠΠ°ΡΡΡΠΎΠΉΠΊΠ°
ΠΠ° ΡΠ²ΡΡΠ·Π²Π°Π½Π΅ Ρ AMQ Online Π½Π° Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡΠ΅ Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠ° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π·Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ: ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π½Π° ΠΊΠΎΠ½Π΅ΠΊΡΠΎΡΠ° Quarkus, ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π·Π° AMQP ΠΊΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° ΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΈ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΎΠ½Π½ΠΈ Π΄Π°Π½Π½ΠΈ. ΠΠΎ-Π΄ΠΎΠ±ΡΠ΅ Π΅ Π΄Π° Π΄ΡΡΠΆΠΈΠΌ Π²ΡΠΈΡΠΊΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΎΠ½Π½ΠΈ Π΄Π°Π½Π½ΠΈ Π½Π° Π΅Π΄Π½ΠΎ ΠΌΡΡΡΠΎ, Π½ΠΎ Π·Π° ΡΠ΅Π»ΠΈΡΠ΅ Π½Π° Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠ°ΡΠΈΡΡΠ° ΡΠ΅ Π³ΠΈ ΡΠ°Π·Π΄Π΅Π»ΠΈΠΌ, Π·Π° Π΄Π° ΠΏΠΎΠΊΠ°ΠΆΠ΅ΠΌ Π²ΡΠ·ΠΌΠΎΠΆΠ½ΠΈΡΠ΅ Π²Π°ΡΠΈΠ°Π½ΡΠΈ Π·Π° Π½Π°ΡΡΡΠΎΠΉΠΊΠ° Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ Quarkus.
ΠΠΎΠ½Π΅ΠΊΡΠΎΡΠΈ
ΠΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ° Π½Π° ΠΊΠΎΠ½Π΅ΠΊΡΠΎΡΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π΅Π½Π° ΠΏΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΠΊΠΎΠΌΠΏΠΈΠ»Π°ΡΠΈΡΡΠ° ΡΡΠ΅Π· ΡΠ°ΠΉΠ» Ρ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ:
mp.messaging.outgoing.orders.connector=smallrye-amqp
mp.messaging.incoming.orders.connector=smallrye-amqp
ΠΠ° ΠΎΠΏΡΠΎΡΡΡΠ²Π°Π½Π΅ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΎΠΏΠ°ΡΠΊΠ° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ ΡΠ°ΠΌΠΎ Π·Π° Π°Π΄ΡΠ΅ΡΠ° βordersβ. Π Π°Π΄ΡΠ΅ΡΡΡ βconfirmationsβ Π² Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° ΠΎΠΏΠ°ΡΠΊΠ° Π² ΠΏΠ°ΠΌΠ΅ΡΡΠ°.
AMQP ΠΊΡΠ°ΠΉΠ½Π° ΡΠΎΡΠΊΠ°
ΠΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΠΊΠΎΠΌΠΏΠΈΠ»Π°ΡΠΈΡΡΠ° ΠΈΠΌΠ΅ΡΠΎ Π½Π° Ρ ΠΎΡΡΠ° ΠΈ Π½ΠΎΠΌΠ΅ΡΠ° Π½Π° ΠΏΠΎΡΡΠ° Π·Π° AMQP ΠΊΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° Π½Π΅ ΡΠ° ΠΈΠ·Π²Π΅ΡΡΠ½ΠΈ, Π·Π°ΡΠΎΠ²Π° ΡΠ΅ ΡΡΡΠ±Π²Π° Π΄Π° Π±ΡΠ΄Π°Ρ ΠΈΠ½ΠΆΠ΅ΠΊΡΠΈΡΠ°Π½ΠΈ. ΠΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ Π·Π°Π΄Π°Π΄Π΅Π½Π° Π² configmap, ΡΡΠ·Π΄Π°Π΄Π΅Π½ ΠΎΡ AMQ Online, Π·Π°ΡΠΎΠ²Π° ΡΠ΅ Π³ΠΈ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΠΌ ΡΡΠ΅Π· ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ° Π² ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ° Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ:
spec:
template:
spec:
containers:
- env:
- name: AMQP_HOST
valueFrom:
configMapKeyRef:
name: quarkus-config
key: service.host
- name: AMQP_PORT
valueFrom:
configMapKeyRef:
name: quarkus-config
key: service.port.amqp
ΠΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΎΠ½Π½ΠΈ Π΄Π°Π½Π½ΠΈ
Π’ΠΎΠΊΠ΅Π½ΡΡ Π·Π° ΡΡΠ»ΡΠ³Π°ΡΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ Π·Π° Π°Π²ΡΠ΅Π½ΡΠΈΠΊΠ°ΡΠΈΡ Π½Π° Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² OpenShift. ΠΠ° ΡΠ΅Π»ΡΠ° ΠΏΡΡΠ²ΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ΠΌ ΠΏΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ ConfigSource, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΠ΅ΡΠ΅ ΡΠΎΠΊΠ΅Π½Π° Π·Π° Π°Π²ΡΠ΅Π½ΡΠΈΠΊΠ°ΡΠΈΡ ΠΎΡ ΡΠ°ΠΉΠ»ΠΎΠ²Π°ΡΠ° ΡΠΈΡΡΠ΅ΠΌΠ° Π½Π° pod-Π°:
public class MessagingCredentialsConfigSource implements ConfigSource {
private static final Set propertyNames;
static {
propertyNames = new HashSet();
propertyNames.add("amqp-username");
propertyNames.add("amqp-password");
}
@Override
public Set getPropertyNames() {
return propertyNames;
}
@Override
public Map getProperties() {
try {
Map properties = new HashMap();
properties.put("amqp-username", "@@serviceaccount@@");
properties.put("amqp-password", readTokenFromFile());
return properties;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public String getValue(String key) {
if ("amqp-username".equals(key)) {
return "@@serviceaccount@@";
}
if ("amqp-password".equals(key)) {
try {
return readTokenFromFile();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
return null;
}
@Override
public String getName() {
return "messaging-credentials-config";
}
private static String readTokenFromFile() throws IOException {
return new String(Files.readAllBytes(Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/token")), StandardCharsets.UTF_8);
}
}
Π‘Π³Π»ΠΎΠ±ΡΠ²Π°Π½Π΅ ΠΈ ΡΠ°Π·Π³ΡΡΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ
Π’ΡΠΉ ΠΊΠ°ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° Π±ΡΠ΄Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠ°Π½ΠΎ Π² ΠΈΠ·ΠΏΡΠ»Π½ΠΈΠΌ ΡΠ°ΠΉΠ», ΡΠ΅ Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠ° Π²ΠΈΡΡΡΠ°Π»Π½Π° ΠΌΠ°ΡΠΈΠ½Π° GraalVM. ΠΠ° ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎΡΠ½ΠΎΡΠ½ΠΎ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°ΡΠ° Π½Π° ΡΠ°Π·ΠΈ ΡΡΠ΅Π΄Π°, Π²ΠΈΠΆΡΠ΅ ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΈΡΠ΅ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈ Π² .
Π‘Π»Π΅Π΄Π²Π°ΠΉΠΊΠΈ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈΡΠ΅ ΡΠ°ΠΌ, ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠ·ΡΠ΅Π³Π»ΠΈΡΠ΅ ΠΈΠ·Ρ ΠΎΠ΄Π½ΠΈΡ ΠΊΠΎΠ΄, Π΄Π° ΠΈΠ·Π²ΡΡΡΠΈΡΠ΅ ΡΠ³Π»ΠΎΠ±ΡΠ²Π°Π½Π΅ΡΠΎ ΠΈ Π΄Π° ΡΠ°Π·Π³ΡΡΡΠ°ΡΠ΅ Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:
git clone https://github.com/EnMasseProject/enmasse-example-clients
cd enmasse-example-clients/quarkus-example-client
oc new-project myapp
mvn -Pnative -Dfabric8.mode=openshift -Dfabric8.build.strategy=docker package fabric8:build fabric8:resource fabric8:apply
Π‘Π»Π΅Π΄ ΡΠ΅Π·ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ ΡΠ΅ Π±ΡΠ΄Π΅ ΡΠ°Π·Π³ΡΡΡΠ°Π½ΠΎ, Π½ΠΎ Π½ΡΠΌΠ° Π΄Π° ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ°, Π΄ΠΎΠΊΠ°ΡΠΎ Π½Π΅ Π½Π°ΡΡΡΠΎΠΈΠΌ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈΡΠ΅ ΡΠ΅ΡΡΡΡΠΈ Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π² AMQ Online.
ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ
Π‘Π΅Π³Π° ΠΎΡΡΠ°Π²Π° Π΄Π° Π·Π°Π΄Π°Π΄Π΅ΠΌ ΡΠ΅ΡΡΡΡΠΈΡΠ΅, ΠΎΡ ΠΊΠΎΠΈΡΠΎ Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠΌΠ° Π½ΡΠΆΠ΄Π° Π² ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ. ΠΠ° ΡΠ΅Π»ΡΠ° ΡΡΡΠ±Π²Π° Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ΠΌ: 1) Π°Π΄ΡΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ, Π·Π° Π΄Π° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠ°ΠΌΠ΅ ΠΊΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ; 2) Π°Π΄ΡΠ΅Ρ, Π·Π° Π΄Π° Π½Π°ΡΡΡΠΎΠΈΠΌ Π°Π΄ΡΠ΅ΡΠΈΡΠ΅, ΠΊΠΎΠΈΡΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π² ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ; 3) ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π» Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ, Π·Π° Π΄Π° Π·Π°Π΄Π°Π΄Π΅ΠΌ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΈΡΠ΅ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΎΠ½Π½ΠΈ Π΄Π°Π½Π½ΠΈ.
ΠΠ΄ΡΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ
ΠΠ±Π΅ΠΊΡΡΡ AddressSpace Π² AMQ Online Π΅ Π³ΡΡΠΏΠ° Π°Π΄ΡΠ΅ΡΠΈ, ΠΊΠΎΠΈΡΠΎ ΡΠΏΠΎΠ΄Π΅Π»ΡΡ ΠΊΡΠ°ΠΉΠ½ΠΈ ΡΠΎΡΠΊΠΈ Π·Π° ΡΠ²ΡΡΠ·Π²Π°Π½Π΅, ΠΊΠ°ΠΊΡΠΎ ΠΈ ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠΈ Π·Π° ΡΠ΄ΠΎΡΡΠΎΠ²Π΅ΡΡΠ²Π°Π½Π΅ ΠΈ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΡ. ΠΡΠΈ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° Π°Π΄ΡΠ΅ΡΠ½ΠΎ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π·Π°Π΄Π°Π΄Π΅ΡΠ΅ ΠΊΠ°ΠΊ ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΠ΅ Π±ΡΠ΄Π°Ρ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π΅Π½ΠΈ ΠΊΡΠ°ΠΉΠ½ΠΈΡΠ΅ ΡΠΎΡΠΊΠΈ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ:
apiVersion: enmasse.io/v1beta1
kind: AddressSpace
metadata:
name: quarkus-example
spec:
type: brokered
plan: brokered-single-broker
endpoints:
- name: messaging
service: messaging
exports:
- name: quarkus-config
kind: configmap
ΠΠ΄ΡΠ΅ΡΠΈ
ΠΠ΄ΡΠ΅ΡΠΈΡΠ΅ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ Π·Π° ΠΈΠ·ΠΏΡΠ°ΡΠ°Π½Π΅ ΠΈ ΠΏΠΎΠ»ΡΡΠ°Π²Π°Π½Π΅ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ. ΠΡΠ΅ΠΊΠΈ Π°Π΄ΡΠ΅Ρ ΠΈΠΌΠ° ΡΠΈΠΏ, ΠΊΠΎΠΉΡΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»Ρ ΡΠ΅ΠΌΠ°Π½ΡΠΈΠΊΠ°ΡΠ° ΠΌΡ, Π° ΡΡΡΠΎ ΡΠ°ΠΊΠ° ΠΈ ΠΏΠ»Π°Π½, ΠΊΠΎΠΉΡΠΎ Π·Π°Π΄Π°Π²Π° ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎΡΠΎ ΡΠ΅Π·Π΅ΡΠ²ΠΈΡΠ°Π½ΠΈ ΡΠ΅ΡΡΡΡΠΈ. ΠΠ΄ΡΠ΅ΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π΅ΡΠΎ ΡΠ°ΠΊΠ°:
apiVersion: enmasse.io/v1beta1
kind: Address
metadata:
name: quarkus-example.orders
spec:
address: orders
type: queue
plan: brokered-queue
ΠΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π» Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ
ΠΠ° Π΄Π° ΠΌΠΎΠ³Π°Ρ Π΄Π° ΠΈΠ·ΠΏΡΠ°ΡΠ°Ρ ΠΈ ΠΏΠΎΠ»ΡΡΠ°Π²Π°Ρ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π½Π° Π²Π°ΡΠΈΡΠ΅ Π°Π΄ΡΠ΅ΡΠΈ ΡΠ°ΠΌΠΎ Π΄ΠΎΠ²Π΅ΡΠ΅Π½ΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Π² ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° ΡΠ΅ ΡΡΠ·Π΄Π°Π΄Π΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π». ΠΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΡΠ°, ΡΠ°Π±ΠΎΡΠ΅ΡΠΈ Π½Π° ΠΊΠ»ΡΡΡΠ΅ΡΠ°, ΠΊΠ»ΠΈΠ΅Π½ΡΠΈΡΠ΅ ΠΌΠΎΠ³Π°Ρ Π΄Π° Π±ΡΠ΄Π°Ρ ΡΠ΄ΠΎΡΡΠΎΠ²Π΅ΡΠ΅Π½ΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° Π°ΠΊΠ°ΡΠ½Ρ Π·Π° ΡΡΠ»ΡΠ³ΠΈ Π² OpenShift. ΠΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΡΡ βserviceaccountβ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ΡΠ°ΠΊΠ°:
apiVersion: user.enmasse.io/v1beta1
kind: MessagingUser
metadata:
name: quarkus-example.app
spec:
username: system:serviceaccount:myapp:default
authentication:
type: serviceaccount
authorization:
- operations: ["send", "recv"]
addresses: ["orders"]
Π Π°Π·ΡΠ΅ΡΠ΅Π½ΠΈΡ Π·Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ
ΠΠ° Π΄Π° ΠΌΠΎΠΆΠ΅ AMQ Online Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ configmap, ΠΊΠΎΠΉΡΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ Π·Π° Π²Π½Π΅Π΄ΡΡΠ²Π°Π½Π΅ Π½Π° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π·Π° ΠΊΡΠ°ΠΉΠ½Π°ΡΠ° ΡΠΎΡΠΊΠ° AMQP, Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° ΡΠ΅ Π·Π°Π΄Π°Π΄Π΅ ΡΠΎΠ»Ρ ΠΈ ΠΏΡΠΈΠ²ΡΡΠ·Π²Π°Π½Π΅ Π½Π° ΡΠΎΠ»Ρ (Role ΠΈ RoleBinding):
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: quarkus-config
spec:
rules:
- apiGroups: [ "" ]
resources: [ "configmaps" ]
verbs: [ "create" ]
- apiGroups: [ "" ]
resources: [ "configmaps" ]
resourceNames: [ "quarkus-config" ]
verbs: [ "get", "update", "patch" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: quarkus-config
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: quarkus-config
subjects:
- kind: ServiceAccount
name: address-space-controller
namespace: amq-online-infra
ΠΠ°ΠΊ Π΄Π° ΠΏΡΠΈΠ»ΠΎΠΆΠΈΡΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ
ΠΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ° Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½Π° ΠΏΠΎ ΡΠ»Π΅Π΄Π½ΠΈΡ Π½Π°ΡΠΈΠ½:
cd enmasse-example-clients/quarkus-example-client
oc project myapp
oc apply -f src/main/resources/k8s/addressspace
oc apply -f src/main/resources/k8s/address
ΠΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ
ΠΠ° Π΄Π° ΡΠ΅ ΡΠ²Π΅ΡΠΈΠΌ, ΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ Π΅ ΡΡΠ°ΡΡΠΈΡΠ°Π½ΠΎ, Π½Π° ΠΏΡΡΠ²ΠΎ ΠΌΡΡΡΠΎ Π΄Π° ΠΏΡΠΎΠ²Π΅ΡΠΈΠΌ Π΄Π°Π»ΠΈ ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΈΡΠ΅ Π°Π΄ΡΠ΅ΡΠΈ ΡΠ° ΡΡΠ·Π΄Π°Π΄Π΅Π½ΠΈ ΠΈ Π°ΠΊΡΠΈΠ²Π½ΠΈ:
until [[ `oc get address quarkus-example.prices -o jsonpath='{.status.phase}'` == "Active" ]]; do echo "ΠΡΠ΅ ΠΎΡΠ΅ Π½Π΅ Π΅ Π³ΠΎΡΠΎΠ²ΠΎ"; sleep 5; done
Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° ΡΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΈΠΌ URL Π°Π΄ΡΠ΅ΡΠ° Π½Π° ΠΌΠ°ΡΡΡΡΡΠ° Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ (ΠΏΡΠΎΡΡΠΎ ΡΠ΅ ΠΎΡΠ²ΠΎΡΠΈΠΌ ΡΠΎΠ·ΠΈ Π°Π΄ΡΠ΅Ρ Π² Π±ΡΠ°ΡΠ·ΡΡΠ°):
echo "http://$(oc get route quarkus-example-client -o jsonpath='{.spec.host}')/prices.html"
Π Π±ΡΠ°ΡΠ·ΡΡΠ° ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ΅ Π²ΠΈΠΆΠ΄Π°, ΡΠ΅ ΡΠΈΠΊΠ΅ΡΠΈΡΠ΅ ΠΏΠ΅ΡΠΈΠΎΠ΄ΠΈΡΠ½ΠΎ ΡΠ΅ ΠΎΠ±Π½ΠΎΠ²ΡΠ²Π°Ρ, Π΄ΠΎΠΊΠ°ΡΠΎ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡΡΠ° ΡΠ΅ ΠΈΠ·ΠΏΡΠ°ΡΠ°Ρ ΠΈ ΠΏΠΎΠ»ΡΡΠ°Π²Π°Ρ ΠΎΡ AMQ Online.
ΠΠ±ΠΎΠ±ΡΠ°Π²Π°ΠΌΠ΅
Π ΡΠ°ΠΊΠ°, Π½Π°ΠΏΠΈΡΠ°Ρ ΠΌΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Quarkus, ΠΊΠΎΠ΅ΡΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° AMQP Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ, Π½Π°ΡΡΡΠΎΠΈΡ ΠΌΠ΅ ΡΠΎΠ²Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π° ΡΠ°Π±ΠΎΡΠΈ Π½Π° ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ°ΡΠ° Red Hat OpenShift ΠΈ Π²Π½Π΅Π΄ΡΠΈΡ ΠΌΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ° ΠΌΡ Π½Π° Π±Π°Π·Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ° Π½Π° AMQ Online. Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° ΡΡΠ·Π΄Π°Π΄ΠΎΡ ΠΌΠ΅ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠΈΡΠ΅, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈ Π·Π° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΡ Π·Π° Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.
Π‘ ΡΠΎΠ²Π° Π·Π°Π²ΡΡΡΠ²Π°ΠΌΠ΅ ΡΠ΅ΡΠΈΡΡΠ° Π·Π° Quarkus, Π½ΠΎ Π½ΠΈ ΠΎΡΠ°ΠΊΠ²Π°Ρ ΠΌΠ½ΠΎΠ³ΠΎ Π½ΠΎΠ²ΠΈΠ½ΠΈ ΠΈ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΈ Π½Π΅ΡΠ°, ΠΎΡΡΠ°Π½Π΅ΡΠ΅ Ρ Π½Π°Ρ!
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: habr.com
