ΠΡΠ΅ΠΌ ΠΏΡΠΈΠ²Π΅Ρ, ΠΈ Ρ Π²Π°ΠΌΠΈ ΡΡΠ΅ΡΠΈΠΉ ΠΏΠΎΡΡ ΠΈΠ· ΡΠ΅ΡΠΈΠΈ ΠΏΡΠΎ Quarkus!
ΠΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ Java-ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠΎΠ² ΡΠ°ΡΡΠΎ ΡΡΠΈΡΠ°Π΅ΡΡΡ, ΡΡΠΎ
ΠΡΠ»ΠΈ ΡΡΡΡ ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅, ΡΠΎ ΡΠ½Π°ΡΠ°Π»Π° ΠΌΡ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ ΠΎΠ±Π»Π°ΡΡΡ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΡ ΠΈ Π΄Π΅ΡΠ°Π»ΠΈ ΡΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ Spring, ΡΡΠΎΠ±Ρ ΠΏΠΎΠΊΠ°Π·Π°ΡΡ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ MicroProfile API Π² ΡΠ²ΠΎΠ΅ΠΉ ΠΏΠΎΠ²ΡΠ΅Π΄Π½Π΅Π²Π½ΠΎΠΉ ΡΠ°Π±ΠΎΡΠ΅. ΠΠ°ΡΠ΅ΠΌ ΠΌΡ ΡΠ°ΡΡΠΊΠ°ΠΆΠ΅ΠΌ ΠΎ MicroProfile API, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΡΠΈΠ³ΠΎΠ΄ΡΡΡΡ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ ΠΏΡΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠΎΠ².
ΠΠΎΡΠ΅ΠΌΡ ΠΈΠΌΠ΅Π½Π½ΠΎ Quarkus? ΠΠΎ-ΠΏΠ΅ΡΠ²ΡΡ
, ΡΡΠΎ ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π²ΠΆΠΈΠ²ΡΡ (live coding), ΡΠΎ Π΅ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΠ° Π»ΡΠ±ΡΡ
ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² MicroProfile API, Spring API ΠΈ Π΄ΡΡΠ³ΠΈΡ
Java API, ΠΊΠΎΡΠΎΡΠ°Ρ Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ Π²ΡΠ΅Π³ΠΎ ΠΎΠ΄Π½ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ: mvn quarkus:dev. ΠΠΎ-Π²ΡΠΎΡΡΡ
, ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΠΌΡΠΉ Π²
ΠΡ Π½Π΅ Π±ΡΠ΄Π΅ΠΌ ΡΠ³Π»ΡΠ±Π»ΡΡΡΡΡ Π² ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΡΡΠΈ MicroProfile, Π° Π»ΠΈΡΡ ΠΏΠΎΡΡΠ°ΡΠ°Π΅ΠΌΡΡ ΠΏΠΎΠΌΠΎΡΡ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ ΠΏΠΎΠ½ΡΡΡ, ΠΊΠ°ΠΊ Π² Quarkus ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ Spring Π²ΠΌΠ΅ΡΡΠ΅ Ρ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°ΠΌΠΈ MicroProfile.
ΠΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΡ ΠΈ Kubernetes
Π§ΡΠΎΠ±Ρ Π½Π΅ ΠΏΠ΅ΡΠ΅Π³ΡΡΠΆΠ°ΡΡ ΡΡΡ ΡΡΠ°ΡΡΡ, ΠΌΡ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ Π·Π΄Π΅ΡΡ Π»ΠΈΡΡ Π²ΡΡΠΎΠΊΠΎΡΡΠΎΠ²Π½Π΅Π²ΡΠ΅ Π°ΡΠΏΠ΅ΠΊΡΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΈ
Quarkus ΡΠ°ΠΊΠΆΠ΅
Π Π½Π°ΠΊΠΎΠ½Π΅Ρ, ΠΎΡΠΈΠ΅Π½ΡΠΈΡΡΡΡΡ Π½Π° Kubernetes ΠΊΠ°ΠΊ Π½Π° ΡΠ΅Π»Π΅Π²ΡΡ ΡΡΠ΅Π΄Ρ ΡΠ°Π·Π²Π΅ΡΡΡΠ²Π°Π½ΠΈΡ, Quarkus Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ Java-ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠΈ Π² ΡΠ΅Ρ ΡΠ»ΡΡΠ°ΡΡ , ΠΊΠΎΠ³Π΄Π° Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΡΠΉ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π» ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Π½Π° ΡΡΠΎΠ²Π½Π΅ ΡΠ°ΠΌΠΎΠΉ ΠΏΠ»Π°ΡΡΠΎΡΠΌΡ Kubernetes. Π ΡΠ°Π±Π»ΠΈΡΠ΅ 1 ΠΏΡΠΈΠ²ΠΎΠ΄ΠΈΡΡΡ ΠΊΠ°ΡΡΠ° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΡ Kubernetes ΠΈ ΡΠΈΠΏΠΎΠ²ΡΡ Java-ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠΎΠ², ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌΡΡ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌΠΈ.
Π’Π°Π±Π»ΠΈΡΠ° 1. ΠΠ°ΡΡΠ° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΡ Java-ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠΎΠ² ΠΈ Kubernetes.
Π€ΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»
Π’ΡΠ°Π΄ΠΈΡΠΈΠΎΠ½Π½ΡΠΉ Spring Boot
Kubernetes
Service discovery
Eureka
DNS
Configuration
Spring Cloud Config
Config Maps / Secrets
Load balancing
Ribbon (Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°)
Service, Replication Controller(Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΡΠ΅ΡΠ²Π΅ΡΠ°)
ΠΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΡ ΠΈ Π·Π°ΠΏΡΡΠΊ ΠΊΠΎΠ΄Π° ΠΈΠ· ΠΏΡΠΈΠΌΠ΅ΡΠ°
Π ΡΡΠΎΠΉ ΡΡΠ°ΡΡΠ΅ ΠΌΡ ΡΡΡΠ»Π°Π΅ΠΌΡΡ Π½Π°
API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ Spring Framework
Dependency Injection
Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠ΅Π»ΡΠΉ ΡΡΠ΄
Π
Π’Π°Π±Π»ΠΈΡΠ° 2. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² Spring DI.
ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Spring DI
ΠΡΠΈΠΌΠ΅ΡΡ
Constructor Injection
public PersonSpringController(
PersonSpringRepository personRepository, // injected
PersonSpringMPService personService) { // injected
this.personRepository = personRepository;
this.personService = personService;
}
Field Injection
@Autowired
@RestClient
SalutationRestClient salutationRestClient;
@Value("${fallbackSalutation}")
String fallbackSalutation;
@Configuration
@Configuration
public class AppConfiguration {
@Bean(name = "capitalizeFunction")
public StringFunction capitalizer() {
return String::toUpperCase;
}
}
@Component("noopFunction")
public class NoOpSingleStringFunction implements StringFunction {
@Override
public String apply(String s) {
return s;
}
}
@Service
public class MessageProducer {
@Value("${greeting.message}")
String message;
public String getPrefix() {
return message;
}
}
ΠΠ΅Π±-ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊ
ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΠΌ MicroProfile ΠΏΠΎΠ½ΡΠ°Π²ΠΈΡΡΡ, ΡΡΠΎ Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ JAX-RS, MicroProfile Rest Client, JSON-P ΠΈ JSON-B Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²Π΅Π±-ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΈΡΠΎΠ²Π°Π½ΠΈΡ. Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ² ΠΏΡΠΈΡΡΠ½ΠΎ ΠΏΠΎΡΠ°Π΄ΡΠ΅Ρ Π½Π΅Π΄Π°Π²Π½ΠΎ ΠΏΠΎΡΠ²ΠΈΠ²ΡΠ°ΡΡΡ Π² Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° Spring Web API, Π² ΡΠ°ΡΡΠ½ΠΎΡΡΠΈ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ², ΠΎΡΠ²Π΅ΡΠ°ΡΡΠΈΡ
Π·Π° REST. ΠΠΎ Π°Π½Π°Π»ΠΎΠ³ΠΈΠΈ ΡΠΎ Spring DI Π³Π»Π°Π²Π½Π°Ρ ΡΠ΅Π»Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΈ Spring Web API Π·Π°ΠΊΠ»ΡΡΠ°Π΅ΡΡΡ Π² ΡΠΎΠΌ, ΡΡΠΎΠ±Ρ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΌΠΎΠ³Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ Spring Web Π²ΠΌΠ΅ΡΡΠ΅ Ρ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°ΠΌΠΈ MicroProfile. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ
Spring Web API ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ 3, Π° Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΡΠ²Π΅Π΄Π΅Π½ΠΈΡ ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΡ Π½Π° ΡΡΡ ΡΠ΅ΠΌΡ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡΠΈ Π² ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²Π΅ Quarkus, ΠΊΠΎΡΠΎΡΠΎΠ΅ Π½Π°Π·ΡΠ²Π°Π΅ΡΡΡ
Π’Π°Π±Π»ΠΈΡΠ° 3. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² Spring Web.
ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Spring Web
ΠΡΠΈΠΌΠ΅ΡΡ
@RestController
@RequestMapping
@RestController
@RequestMapping("/person")
public class PersonSpringController {
...
...
...
}
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestParam
@RequestHeader
@MatrixVariable
@PathVariable
@CookieValue
@RequestBody
@ResponseStatus
@ExceptionHandler
@RestControllerAdvice (partial)
@GetMapping(path = "/greet/{id}",
produces = "text/plain")
public String greetPerson(
@PathVariable(name = "id") long id) {
...
...
...
}
Spring Data JPA
ΠΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΠΌ MicroProfile ΡΠ°ΠΊΠΆΠ΅ ΠΏΡΠΈΠ΄Π΅ΡΡΡ ΠΏΠΎ Π΄ΡΡΠ΅, ΡΡΠΎ Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ JPA Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Hibernate ORM. ΠΠ»Ρ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ² ΡΠΎΠΆΠ΅ Π΅ΡΡΡ Ρ
ΠΎΡΠΎΡΠ°Ρ Π½ΠΎΠ²ΠΎΡΡΡ: Quarkus ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΠΎΠ±ΡΠ΅ΠΏΡΠΈΠ½ΡΡΡΠ΅ Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΈ ΠΈ ΡΠΈΠΏΡ Spring Data JPA. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ
Spring Data JPA API ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ 4.
Π
Π’Π°Π±Π»ΠΈΡΠ° 4. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² Spring Data JPA.
ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Spring Data JPA
ΠΡΠΈΠΌΠ΅ΡΡ
CrudRepository
public interface PersonRepository
extends JpaRepository,
PersonFragment {
...
}
Repository
JpaRepository
PagingAndSortingRepository
public class PersonRepository extends
Repository {
Person save(Person entity);
Optional findById(Person entity);
}
Repository Fragments
public interface PersonRepository
extends JpaRepository,
PersonFragment {
...
}
Derived query methods
public interface PersonRepository extends CrudRepository {
List findByName(String name);
Person findByNameBySsn(String ssn);
Optional
findByNameBySsnIgnoreCase(String ssn);
Boolean existsBookByYearOfBirthBetween(
Integer start, Integer end);
}
User-defined queries
public interface MovieRepository
extends CrudRepository {
Movie findFirstByOrderByDurationDesc();
@Query("select m from Movie m where m.rating = ?1")
Iterator findByRating(String rating);
@Query("from Movie where title = ?1")
Movie findByTitle(String title);
}
API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ MicroProfile
ΠΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΡ (Fault tolerance)
ΠΠΎΠ½ΡΡΡΡΠΊΡΠΈΠΈ Fault tolerance ΠΎΡΠ΅Π½Ρ Π²Π°ΠΆΠ½Ρ Π΄Π»Ρ ΠΏΡΠ΅Π΄ΠΎΡΠ²ΡΠ°ΡΠ΅Π½ΠΈΡ ΠΊΠ°ΡΠΊΠ°Π΄Π½ΡΡ
ΠΎΡΠΊΠ°Π·ΠΎΠ² ΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ Π½Π°Π΄Π΅ΠΆΠ½ΡΡ
ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ½ΡΡ
Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡ. Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΡΠΆΠ΅ ΠΌΠ½ΠΎΠ³ΠΎ Π»Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ Π΄Π»Ρ ΠΎΡΠΊΠ°Π·ΠΎΡΡΡΠΎΠΉΡΠΈΠ²ΠΎΡΡΠΈ circuit-breakerβΡ
Π’Π°Π±Π»ΠΈΡΠ° 5. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² MicroProfile Fault Tolerance.
Π€ΡΠ½ΠΊΡΠΈΠΈ MicroProfile Fault Tolerance
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
ΠΡΠΈΠΌΠ΅ΡΡ
@Asynchronous
ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π»ΠΎΠ³ΠΈΠΊΠΈ Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎΠΌ ΠΏΠΎΡΠΎΠΊΠ΅
@Asynchronous
@Retry
public Future<String> getSalutation() {
...
return future;
}
@Bulkhead
ΠΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ Π·Π°ΠΏΡΠΎΡΠΎΠ²
@Bulkhead(5)
public void fiveConcurrent() {
makeRemoteCall(); //...
}
@CircuitBreaker
Π£ΠΌΠ½Π°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠ±ΠΎΠ΅Π² ΠΈ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡΠ»Π΅ ΡΠ±ΠΎΠ΅Π²
@CircuitBreaker(delay=500 // milliseconds
failureRatio = .75,
requestVolumeThreshold = 20,
successThreshold = 5)
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
makeRemoteCall(); //...
}
@Fallback
ΠΡΠ·ΠΎΠ² Π°Π»ΡΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π½ΠΎΠΉ Π»ΠΎΠ³ΠΈΠΊΠΈ Π² ΡΠ»ΡΡΠ°Π΅ ΡΠ±ΠΎΡ
@Timeout(500) // milliseconds
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
makeRemoteCall(); //...
}
public String fallback() {
return "hello";
}
ΠΠΎΠ²ΡΠΎΡ ΠΏΡΠΈ ΡΠ±ΠΎΠ΅ Π·Π°ΠΏΡΠΎΡΠ°
@Retry(maxRetries=3)
public String getSalutation() {
makeRemoteCall(); //...
}
ΠΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎΠ΅ Π²ΡΠ΅ΠΌΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ ΠΏΡΠΈ ΡΠ±ΠΎΠ΅
@Timeout(value = 500 ) // milliseconds
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
makeRemoteCall(); //...
}
ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΠ΅ΡΠ²ΠΈΡΠΎΠ² (Service Health)
Kubernetes-ΠΏΠ»Π°ΡΡΠΎΡΠΌΡ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΡΡ ΠΈΡΠΏΡΠ°Π²Π½ΠΎΡΡΡ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠΎΠ² Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΡΡ
ΡΠ΅ΡΠ²ΠΈΡΠΎΠ². Π§ΡΠΎΠ±Ρ Π½ΠΈΠΆΠ΅Π»Π΅ΠΆΠ°ΡΠ°Ρ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ° ΠΌΠΎΠ³Π»Π° ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΡΡ ΡΠ΅ΡΠ²ΠΈΡΡ, Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΎΠ±ΡΡΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΡΠ΅ HealthIndicator ΠΈ Spring Boot Actuator. Π Quarkus ΡΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ MicroProfile Health, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π²ΡΠΏΠΎΠ»Π½ΡΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΊΡ ΡΠ°Π±ΠΎΡΠΎΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡΠΈ (liveness check), Π½ΠΎ ΠΌΠΎΠ³ΡΡ Π±ΡΡΡ Π½Π°ΡΡΡΠΎΠ΅Π½Ρ ΠΈ Π½Π° ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΊΡ liveness ΠΈ readiness (Π³ΠΎΡΠΎΠ²Π½ΠΎΡΡΠΈ). ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ
MicroProfile Health API ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ 6, Π° Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½Π°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½Π° Π² ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²Π΅ Quarkus
Π’Π°Π±Π»ΠΈΡΠ° 6. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² MicroProfile Health.
Π€ΡΠ½ΠΊΡΠΈΠΈ MicroProfile Health
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
ΠΡΠΈΠΌΠ΅ΡΡ
@Liveness
ΠΠ»Π°ΡΡΠΎΡΠΌΠ° Π²ΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΡ Π½Π΅ΠΈΡΠΏΡΠ°Π²Π½ΡΡ
ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠΈΠ·ΠΎΠ²Π°Π½Π½ΡΡ
ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ
Endpoint:
host:8080/health/live
@Liveness
public class MyHC implements HealthCheck {
public HealthCheckResponse call() {
...
return HealthCheckResponse
.named("myHCProbe")
.status(ready ? true:false)
.withData("mydata", data)
.build();
}
@Readiness
ΠΠ»Π°ΡΡΠΎΡΠΌΠ° Π½Π΅ Π±ΡΠ΄Π΅Ρ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ ΡΡΠ°ΡΠΈΠΊ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π² ΡΠ»ΡΡΠ°Π΅ Π΅Π³ΠΎ Π½Π΅Π³ΠΎΡΠΎΠ²Π½ΠΎΡΡΠΈ
Endpoint:
host:8080/health/ready
@Readiness
public class MyHC implements HealthCheck {
public HealthCheckResponse call() {
...
return HealthCheckResponse
.named("myHCProbe")
.status(live ? true:false)
.withData("mydata", data)
.build();
}
ΠΠ΅ΡΡΠΈΠΊΠΈ
ΠΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡ ΠΌΠ΅ΡΡΠΈΠΊΠΈ ΠΈΠ»ΠΈ Π² ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½ΡΡ ΡΠ΅Π»ΡΡ (Π΄Π»Ρ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ SLA-ΠΏΠΎΠΊΠ°Π·Π°ΡΠ΅Π»Π΅ΠΉ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ), ΠΈΠ»ΠΈ Π² Π½Π΅ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½ΡΡ (Π±ΠΈΠ·Π½Π΅Ρ-ΠΏΠΎΠΊΠ°Π·Π°ΡΠ΅Π»ΠΈ SLA). Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡ ΠΌΠ΅ΡΡΠΈΠΊΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Spring Boot Actuator ΠΈ Micrometer. Π ΡΠ²ΠΎΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ, Quarkus ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ MicroProfile Metrics Π΄Π»Ρ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»Π΅Π½ΠΈΡ Π±Π°Π·ΠΎΠ²ΡΡ ΠΌΠ΅ΡΡΠΈΠΊ (JVM ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½Π°Ρ ΡΠΈΡΡΠ΅ΠΌΠ°), Π²Π΅Π½Π΄ΠΎΡ-ΠΌΠ΅ΡΡΠΈΠΊ (Quarkus) ΠΈ ΠΌΠ΅ΡΡΠΈΠΊ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. MicroProfile Metrics ΡΡΠ΅Π±ΡΠ΅Ρ, ΡΡΠΎΠ±Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π»Π° Π²ΡΡ ΠΎΠ΄Π½ΡΠ΅ ΡΠΎΡΠΌΠ°ΡΡ JSON ΠΈ OpenMetrics (Prometheus). ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ MicroProfile Metrics API ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ 7.
Π
Π’Π°Π±Π»ΠΈΡΠ° 7. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² MicroProfile Metrics.
Π€ΡΠ½ΠΊΡΠΈΠΈ MicroProfile Metrics
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
ΠΡΠΈΠΌΠ΅ΡΡ
@Counted
ΠΠ±ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ counter-ΡΡΠ΅ΡΡΠΈΠΊ, ΠΏΠΎΠ΄ΡΡΠΈΡΡΠ²Π°ΡΡΠΈΠΉ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π²ΡΠ·ΠΎΠ²ΠΎΠ² Π°Π½Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
@Counted(name = "fallbackCounter",
displayName = "Fallback Counter",
description = "Fallback Counter")
public String salutationFallback() {
return fallbackSalutation;
}
@ConcurrentGauge
ΠΠ±ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ gauge-Π΄Π°ΡΡΠΈΠΊ, ΠΏΠΎΠ΄ΡΡΠΈΡΡΠ²Π°ΡΡΠΈΠΉ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΡΡ Π²ΡΠ·ΠΎΠ²ΠΎΠ² Π°Π½Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
@ConcurrentGuage(
name = "fallbackConcurrentGauge",
displayName="Fallback Concurrent",
description="Fallback Concurrent")
public String salutationFallback() {
return fallbackSalutation;
}
@Gauge
ΠΠ±ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ gauge-Π΄Π°ΡΡΠΈΠΊ, Π·Π°ΠΌΠ΅ΡΡΡΡΠΈΠΉ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ Π°Π½Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
@Metered(name = "FallbackGauge",
displayName="Fallback Gauge",
description="Fallback frequency")
public String salutationFallback() {
return fallbackSalutation;
}
@Metered
ΠΠ±ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ meter-Π΄Π°ΡΡΠΈΠΊ, ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΡΡΠΈΠΉ ΡΠ°ΡΡΠΎΡΡ Π²ΡΠ·ΠΎΠ²Π° Π°Π½Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
@Metered(name = "MeteredFallback",
displayName="Metered Fallback",
description="Fallback frequency")
public String salutationFallback() {
return fallbackSalutation;
}
ΠΠ½Π½ΠΎΡΠ°ΡΠΈΡ, ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΠ°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΡ , ΠΏΡΠΈ ΠΏΠΎΡΡΡΠΏΠ»Π΅Π½ΠΈΠΈ Π·Π°ΠΏΡΠΎΡΠ° Π½Π° Π²Π½Π΅ΡΠ΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΡΡΠ²ΠΎ ΠΌΠ΅ΡΡΠΈΠΊΠΈ
@Metric
@Metered(name = "MeteredFallback",
displayName="Metered Fallback",
description="Fallback frequency")
public String salutationFallback() {
return fallbackSalutation;
}
ΠΠ±ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ ΡΠ°ΠΉΠΌΠ΅Ρ, ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΡΡΠΈΠΉ Π΄Π»ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ Π°Π½Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°
@Timed(name = "TimedFallback",
displayName="Timed Fallback",
description="Fallback delay")
public String salutationFallback() {
return fallbackSalutation;
}
ΠΠΎΠ½Π΅ΡΠ½ΡΠ΅ ΡΠΎΡΠΊΠΈ ΠΌΠ΅ΡΡΠΈΠΊ (Metrics Endpoints)
ΠΠ΅ΡΡΠΈΠΊΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ
ΠΠ°Π·ΠΎΠ²ΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ
ΠΠ΅Π½Π΄ΠΎΡ-ΠΌΠ΅ΡΡΠΈΠΊΠΈ
ΠΡΠ΅ ΠΌΠ΅ΡΡΠΈΠΊΠΈ
Rest-ΠΊΠ»ΠΈΠ΅Π½Ρ MicroProfile
ΠΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΡ ΡΠ°ΡΡΠΎ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡ ΠΊΠΎΠ½Π΅ΡΠ½ΡΠ΅ ΡΠΎΡΠΊΠΈ RESTful, Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΊΠΎΡΠΎΡΡΠΌΠΈ ΡΡΠ΅Π±ΡΡΡΡΡ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΈΠ΅ API. Π§ΡΠΎΠ±Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΊΠΎΠ½Π΅ΡΠ½ΡΠ΅ ΡΠΎΡΠΊΠΈ RESTful, Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΎΠ±ΡΡΠ½ΠΎ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ RestTemplate. Quarkus ΠΆΠ΅ ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ Π΄Π»Ρ ΡΠ΅ΡΠ΅Π½ΠΈΡ ΡΡΠΎΠΉ Π·Π°Π΄Π°ΡΠΈ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ MicroProfile Rest Client, ΠΏΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΊΠΎΡΠΎΡΡΡ ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ 8.
Π
Π’Π°Π±Π»ΠΈΡΠ° 8. ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² MicroProfile Rest Client.
Π€ΡΠ½ΠΊΡΠΈΠΈ MicroProfile Rest Client
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅
ΠΡΠΈΠΌΠ΅ΡΡ
@RegisterRestClient
Π Π΅Π³ΠΈΡΡΡΠΈΡΡΠ΅Ρ ΡΠΈΠΏΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ Java-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° REST
@RegisterRestClient
@Path("/")
public interface MyRestClient {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getSalutation();
}
@RestClient
ΠΡΠΌΠ΅ΡΠ°Π΅Ρ Π²Π½Π΅Π΄ΡΠ΅Π½ΠΈΠ΅ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΠ° ΡΠΈΠΏΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° REST-ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
@Autowired // or @Inject
@RestClient
MyRestClient restClient;
Invocation
ΠΡΠ·ΡΠ²Π°Π΅Ρ ΠΊΠΎΠ½Π΅ΡΠ½ΡΡ ΡΠΎΡΠΊΡ REST
System.out.println(
restClient.getSalutation());
mp-rest/url
ΠΠ°Π΄Π°Π΅Ρ ΠΊΠΎΠ½Π΅ΡΠ½ΡΡ ΡΠΎΡΠΊΡ REST
application.properties:
org.example.MyRestClient/mp-rest/url=
http://localhost:8081/myendpoint
ΠΡΠΎΠ³ΠΈ
Π ΡΡΠΎΠΌ Π±Π»ΠΎΠ³Π΅, ΠΊΠΎΡΠΎΡΡΠΉ Π² ΠΏΠ΅ΡΠ²ΡΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΠΏΡΠΈΠ³ΠΎΠ΄ΠΈΡΡΡ Spring-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ, ΠΌΡ ΠΊΡΠ°ΡΠΊΠΎ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π»ΠΈ, ΠΊΠ°ΠΊ Π² Quarkus ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ Spring Π²ΠΌΠ΅ΡΡΠ΅ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°ΠΌΠΈ MicroProfile, ΡΡΠΎΠ±Ρ ΡΠ°Π·ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΡ Java ΠΈ Π·Π°ΡΠ΅ΠΌ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°ΡΡ ΠΈΡ Π² Π½Π°ΡΠΈΠ²Π½ΡΠΉ Π΄Π²ΠΎΠΈΡΠ½ΡΠΉ ΠΊΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ ΡΠΎΡΠ½ΠΈ ΠΌΠ΅Π³Π°Π±Π°ΠΉΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠ²Π½ΠΎΠΉ ΠΏΠ°ΠΌΡΡΠΈ ΠΈ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΡΡΡ Π·Π° ΡΡΠΈΡΠ°Π½Π½ΡΠ΅ ΠΌΠΈΠ»Π»ΠΈΡΠ΅ΠΊΡΠ½Π΄Ρ.
ΠΠ°ΠΊ Π²Ρ ΡΠΆΠ΅ ΠΏΠΎΠ½ΡΠ»ΠΈ, Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΡΠ²Π΅Π΄Π΅Π½ΠΈΡ ΠΎ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ΅ API-ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠ² Spring ΠΈ MicroProfile, Π° ΡΠ°ΠΊΠΆΠ΅ ΠΌΠ°ΡΡΡ Π΄ΡΡΠ³ΠΎΠΉ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡΠΈ Π²
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com