рд╕рдмреИрд▓рд╛рдИ рдирдорд╕реНрдХрд╛рд░, рдпрд╣рд╛рдБ рдХреНрд╡рд╛рд░реНрдХрд╕ рд╢реГрдЩреНрдЦрд▓рд╛рдХреЛ рддреЗрд╕реНрд░реЛ рдкреЛрд╖реНрдЯ рдЫ!
рдЬрд╛рднрд╛ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕реЗрд╕рд╣рд░реВ рд╡рд┐рдХрд╛рд╕ рдЧрд░реНрджрд╛, рдпреЛ рдЕрдХреНрд╕рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдЧрд░рд┐рдиреНрдЫ
рдереЛрд░реИ рд╡рд┐рд╕реНрддрд╛рд░рдорд╛, рд╣рд╛рдореА рдкрд╣рд┐рд▓реЗ рд╕реНрдХреЛрдк рд░ рд╡рд┐рд╡рд░рдгрд╣рд░реВ рд╣реЗрд░реНрдиреЗрдЫреМрдВ рдХрд┐ рдХрд╕рд░реА Quarkus рд▓реЗ Spring APIs рд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрджрдЫ рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓рд╛рдИ рддрд┐рдиреАрд╣рд░реВрдХреЛ рджреИрдирд┐рдХ рдХрд╛рд░реНрдпрдорд╛ рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ API рдХрд╕рд░реА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рднрдиреЗрд░ рджреЗрдЦрд╛рдЙрдиред рддреНрдпрд╕рдкрдЫрд┐ рд╣рд╛рдореА рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдкреАрдЖрдИрд╣рд░реВ рдХрднрд░ рдЧрд░реНрдиреЗрдЫреМрдВ, рдЬреБрди рдорд╛рдЗрдХреНрд░реЛ рд╕реЗрд╡рд╛рд╣рд░реВ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрджрд╛ рд╕реНрдкреНрд░рд┐рдВрдЧ рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрдХрд╛ рд▓рд╛рдЧрд┐ рдЙрдкрдпреЛрдЧреА рд╣реБрдиреНрдЫред
рдХреНрд╡рд╛рд░реНрдХрд╕ рдХрд┐рди ? рд╕рдмреИрднрдиреНрджрд╛ рдкрд╣рд┐рд▓реЗ, рдпреЛ рд▓рд╛рдЗрдн рдХреЛрдбрд┐рдЩ рд╣реЛ, рдЕрд░реНрдерд╛рддреН рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдкреАрдЖрдИ, рд╕реНрдкреНрд░рд┐рдЩ рдПрдкреАрдЖрдИ рд░ рдЕрдиреНрдп рдЬрд╛рднрд╛ рдПрдкреАрдЖрдИрд╣рд░реВрдорд╛ рднрдПрдХрд╛ рдХреБрдиреИ рдкрдирд┐ рдкрд░рд┐рд╡рд░реНрддрдирд╣рд░реВрдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░рд┐рд▓реЛрдбрд┐рдЩ, рдЬреБрди рдХреЗрд╡рд▓ рдПрдЙрдЯрд╛ рдЖрджреЗрд╢рджреНрд╡рд╛рд░рд╛ рдЧрд░рд┐рдиреНрдЫ: mvn quarkus:devред рджреЛрд╕реНрд░реЛ, рдорд╛ рд╡рд┐рдЪрд╛рд░ рдЧрд░рд┐рдпреЛ
рд╣рд╛рдореА рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓рдХреЛ рдмрд╛рд░реЗрдорд╛ рд╡рд┐рд╕реНрддреГрдд рд░реВрдкрдорд╛ рдЬрд╛рдиреЗрдЫреИрдиреМрдВ, рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓рд╛рдИ рдЙрдиреАрд╣рд░реВрд▓реЗ Quarkus рдорд╛ рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ API рд╣рд░реВ рдХрд╕рд░реА Spring APIs рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рд╕рдХреНрдЫрдиреН рднрдиреЗрд░ рдмреБрдЭреНрди рдорджреНрджрдд рдЧрд░реНрди рдмрд╛рд╣реЗрдХред
рдХрдиреНрдЯреЗрдирд░ рд░ Kubernetes
рдпрд╕ рд▓реЗрдЦрд▓рд╛рдИ рд╕рд░рд▓ рд░рд╛рдЦреНрдирдХреЛ рд▓рд╛рдЧрд┐, рд╣рд╛рдореА рдпрд╣рд╛рдБ рд╕рдорд░реНрдердирдХрд╛ рдЙрдЪреНрдЪ-рд╕реНрддрд░рдХрд╛ рдкрдХреНрд╖рд╣рд░реВ рдорд╛рддреНрд░ рд╕рдорд╛рд╡реЗрд╢ рдЧрд░реНрдиреЗрдЫреМрдВред
рдХреНрд╡рд╛рд░реНрдХрд╕ рдкрдирд┐
рдЕрдиреНрддрдорд╛, Kubernetes рд▓рд╛рдИ рд▓рдХреНрд╖рд┐рдд рдкрд░рд┐рдирд┐рдпреЛрдЬрди рд╡рд╛рддрд╛рд╡рд░рдгрдХреЛ рд░реВрдкрдорд╛ рдзреНрдпрд╛рди рдХреЗрдиреНрджреНрд░рд┐рдд рдЧрд░реЗрд░, Quarkus рд▓реЗ рдЬрд╛рднрд╛ рдлреНрд░реЗрдорд╡рд░реНрдХ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджреИрди рдЬрд╣рд╛рдБ рд╕рдорд╛рди рдкреНрд░рдХрд╛рд░реНрдпрддрд╛ Kubernetes рдкреНрд▓реЗрдЯрдлрд░реНрдордХреЛ рд╕реНрддрд░рдорд╛ рд▓рд╛рдЧреВ рдЧрд░рд┐рдПрдХреЛ рдЫред рддрд╛рд▓рд┐рдХрд╛ 1 рд▓реЗ Kubernetes рд░ рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ Java рдлреНрд░реЗрдорд╡рд░реНрдХрд╣рд░реВ рдмреАрдЪрдХреЛ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкрддреНрд░рд╛рдЪрд╛рд░рдХреЛ рдирдХреНрд╕рд╛ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫред
рддрд╛рд▓рд┐рдХрд╛ 1. рдЬрд╛рднрд╛ рдлреНрд░реЗрдорд╡рд░реНрдХ рд░ рдХреБрдмрд░реНрдиреЗрдЯреНрд╕ рдмреАрдЪрдХреЛ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкрддреНрд░рд╛рдЪрд╛рд░рдХреЛ рдирдХреНрд╕рд╛ред
рдХрд╛рд░реНрдпрд╛рддреНрдордХ
рдкрд░рдореНрдкрд░рд╛рдЧрдд рд╡рд╕рдиреНрдд рдмреБрдЯ
рдХреБрдмрд░реНрдиреЗрдЯреНрд╕
рд╕реЗрд╡рд╛ рдЖрд╡рд┐рд╖реНрдХрд╛рд░
рдпреБрд░реЗрдХрд╛
DNS
рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди
рд╡рд╕рдиреНрдд рдХреНрд▓рд╛рдЙрдб рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди
рдирдХреНрд╕рд╛/рдЧреЛрдкреНрдп рдХрдиреНрдлрд┐рдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН
рд▓реЛрдб рдмреНрдпрд╛рд▓реЗрдиреНрд╕рд┐рдВрдЧ
рд░рд┐рдмрди (рдЧреНрд░рд╛рд╣рдХ рдкрдХреНрд╖)
рд╕реЗрд╡рд╛, рдкреНрд░рддрд┐рдХреГрддрд┐ рдирд┐рдпрдиреНрддреНрд░рдХ (рд╕рд░реНрднрд░ рд╕рд╛рдЗрдб)
рдЙрджрд╛рд╣рд░рдгрдмрд╛рдЯ рдХреЛрдб рдХрдореНрдкрд╛рдЗрд▓ рд░ рдЪрд▓рд╛рдЙрдиреБрд╣реЛрд╕реН
рдпрд╕ рд▓реЗрдЦрдорд╛ рд╣рд╛рдореА рд╕рдиреНрджрд░реНрдн рдЧрд░реНрдЫреМрдВ
рд╡рд╕рдиреНрдд рдлреНрд░реЗрдорд╡рд░реНрдХ API рд╣рд░реВ
рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди
рдХреНрд╡рд╛рд░реНрдХрд╕рд▓реЗ рджрд╛рдпрд░рд╛рд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрджрдЫ
╨Т
рддрд╛рд▓рд┐рдХрд╛ реи. рд╕рдорд░реНрдерд┐рдд Spring DI APIs рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд DI рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рдЙрджрд╛рд╣рд░рдг
рдХрдиреНрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдЗрдВрдЬреЗрдХреНрд╢рди
public PersonSpringController(
PersonSpringRepository personRepository, // injected
PersonSpringMPService personService) { // injected
this.personRepository = personRepository;
this.personService = personService;
}
рдлрд┐рд▓реНрдб рдЗрдВрдЬреЗрдХреНрд╢рди
@Autowired
@RestClient
SalutationRestClient salutationRestClient;
@Value("${fallbackSalutation}")
String fallbackSalutation;
@рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди
@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;
}
}
рд╡реЗрдм рдлреНрд░реЗрдорд╡рд░реНрдХ
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ Quarkus рд▓рд╛рдИ рдкреНрд░рд╛рдердорд┐рдХ рд╡реЗрдм рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдЩ рдореЛрдбреЗрд▓рдХреЛ рд░реВрдкрдорд╛ JAX-RS, MicroProfile Rest Client, JSON-P, рд░ JSON-B рд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрдиреЗ рдХреБрд░рд╛ рдорди рдкрд░рд╛рдЙрдиреЗрдЫрдиреНред рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВ рд╡рд┐рд╢реЗрд╖ REST рдЗрдиреНрдЯрд░рдлреЗрд╕рд╣рд░реВрдорд╛, Spring Web API рдХреЛ рд▓рд╛рдЧрд┐ рдХреНрд╡рд╛рд░реНрдХрд╕рдХреЛ рднрд░реНрдЦрд░рдХреЛ рд╕рдорд░реНрдердирдмрд╛рдЯ рдЦреБрд╕реА рд╣реБрдиреЗрдЫрдиреНред Spring DI рдЬрд╕реНрддреИ, Spring Web API рд╕рдорд░реНрдердирдХреЛ рдореБрдЦреНрдп рд▓рдХреНрд╖реНрдп Spring рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓рд╛рдИ MicroProfile API рд╕рдБрдЧ рд╕рдВрдпреЛрдЬрдирдорд╛ Spring Web APIs рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рд╕рдХреНрд╖рдо рдкрд╛рд░реНрдиреБ рд╣реЛред рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рд╡реЗрдм API рд╣рд░реВ рдХрд╕рд░реА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рднрдиреНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рддрд╛рд▓рд┐рдХрд╛ 3 рдорд╛ рдкреНрд░рджрд╛рди рдЧрд░рд┐рдПрдХреЛ рдЫ, рд░ рдпрд╕ рд╡рд┐рд╖рдпрдорд╛ рдердк рдЬрд╛рдирдХрд╛рд░реА рд░ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рдХреНрд╡рд╛рд░реНрдХрд╕ рдЯреНрдпреБрдЯреЛрд░рд┐рдпрд▓рдорд╛ рдлреЗрд▓рд╛ рдкрд╛рд░реНрди рд╕рдХрд┐рдиреНрдЫред
рддрд╛рд▓рд┐рдХрд╛ 3. рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рд╡реЗрдм API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рд╡реЗрдм рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рдЙрджрд╛рд╣рд░рдг
@RestController
@RequestMapping
@RestController
@RequestMapping("/person")
public class PersonSpringController {
...
...
...
}
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestParam
@RequestHeader
@MatrixVariable
@PathVariable
@CookieValue
@RequestBody
@ResponseStatus
@ExceptionHandler
@RestControllerAdvice (рдЖрдВрд╢рд┐рдХ)
@GetMapping(path = "/greet/{id}",
produces = "text/plain")
public String greetPerson(
@PathVariable(name = "id") long id) {
...
...
...
}
рд╡рд╕рдиреНрдд рдбрд╛рдЯрд╛ JPA
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рд╣рд╛рдЗрдмрд░рдиреЗрдЯ ORM рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдХреНрд╡рд╛рд░реНрдХрд╕рд▓реЗ JPA рд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реЗрдХреЛ рдХреБрд░рд╛рдХреЛ рдкрдирд┐ рдкреНрд░рд╢рдВрд╕рд╛ рдЧрд░реНрдиреЗрдЫрдиреНред рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрдХрд╛ рд▓рд╛рдЧрд┐ рдкрдирд┐ рд░рд╛рдореНрд░реЛ рд╕рдорд╛рдЪрд╛рд░ рдЫ: рдХреНрд╡рд╛рд░реНрдХрд╕рд▓реЗ рд╕рд╛рдзрд╛рд░рдг рд╡рд╕рдиреНрдд рдбрд╛рдЯрд╛ JPA рдПрдиреЛрдЯреЗрд╕рдирд╣рд░реВ рд░ рдкреНрд░рдХрд╛рд░рд╣рд░реВрд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрджрдЫред рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рдбрд╛рдЯрд╛ JPA API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рддрд╛рд▓рд┐рдХрд╛ 4 рдорд╛ рджрд┐рдЗрдПрдХреЛ рдЫред
╨Т
рддрд╛рд▓рд┐рдХрд╛ 4. рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рдбрд╛рдЯрд╛ JPA API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рд╕рдорд░реНрдерд┐рдд рд╡рд╕рдиреНрдд рдбрд╛рдЯрд╛ JPA рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рдЙрджрд╛рд╣рд░рдг
CrudRepository
public interface PersonRepository
extends JpaRepository,
PersonFragment {
...
}
рднрдгреНрдбрд╛рд░
JpaRepository
рдкреЗрдЬрд┐рдЩ рд░ рдХреНрд░рдордмрджреНрдз рднрдгреНрдбрд╛рд░
public class PersonRepository extends
Repository {
Person save(Person entity);
Optional findById(Person entity);
}
рд░рд┐рдкреЛрдЬрд┐рдЯрд░реА рдЯреБрдХреНрд░рд╛рд╣рд░реВ
public interface PersonRepository
extends JpaRepository,
PersonFragment {
...
}
рд╡реНрдпреБрддреНрдкрдиреНрди рдХреНрд╡реЗрд░реА рд╡рд┐рдзрд┐рд╣рд░реВ
public interface PersonRepository extends CrudRepository {
List findByName(String name);
Person findByNameBySsn(String ssn);
Optional
findByNameBySsnIgnoreCase(String ssn);
Boolean existsBookByYearOfBirthBetween(
Integer start, Integer end);
}
рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдкреНрд░рд╢реНрдирд╣рд░реВ
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 рд╣рд░реВ
рджреЛрд╖ рд╕рд╣рд┐рд╖реНрдгреБрддрд╛
рдХреНрдпрд╛рд╕реНрдХреЗрдбрд┐рдЩ рд╡рд┐рдлрд▓рддрд╛рд╣рд░реВ рд░реЛрдХреНрди рд░ рднрд░рдкрд░реНрджреЛ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрднрд┐рд╕ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рд╣рд░реВ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрди рддреНрд░реБрдЯрд┐ рд╕рд╣рд┐рд╖реНрдгреБрддрд╛ рдирд┐рд░реНрдорд╛рдгрд╣рд░реВ рдзреЗрд░реИ рдорд╣рддреНрддреНрд╡рдкреВрд░реНрдг рдЫрдиреНред рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рдзреЗрд░реИ рд╡рд░реНрд╖рджреЗрдЦрд┐ рджреЛрд╖ рд╕рд╣рдирд╢реАрд▓рддрд╛рдХреЛ рд▓рд╛рдЧрд┐ рд╕рд░реНрдХрд┐рдЯ-рдмреНрд░реЗрдХрд░рд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджреИ рдЖрдПрдХрд╛ рдЫрдиреНред
рддрд╛рд▓рд┐рдХрд╛ 5. рд╕рдорд░реНрдерд┐рдд рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рддреНрд░реБрдЯрд┐ рд╕рд╣рд┐рд╖реНрдгреБрддрд╛ API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рджреЛрд╖ рд╕рд╣рд┐рд╖реНрдгреБрддрд╛ рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рд╡рд┐рд╡рд░рдг
рдЙрджрд╛рд╣рд░рдг
@ рдПрд╕рд┐рдиреНрдХреНрд░реЛрдирд╕
рдЕрд▓рдЧ рдереНрд░реЗрдбрдорд╛ рддрд░реНрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЧрд░реНрджреИ
@Asynchronous
@Retry
public Future<String> getSalutation() {
...
return future;
}
@ рдмрд▓реНрдХрд╣реЗрдб
рдПрдХ рд╕рд╛рде рдЕрдиреБрд░реЛрдзрд╣рд░реВрдХреЛ рд╕рдВрдЦреНрдпрд╛ рд╕реАрдорд┐рдд рдЧрд░реНрдиреБрд╣реЛрд╕реН
@Bulkhead(5)
public void fiveConcurrent() {
makeRemoteCall(); //...
}
@рд╕рд░реНрдХрд┐рдЯ рдмреНрд░реЗрдХрд░
рд╕реНрдорд╛рд░реНрдЯ рд╡рд┐рдлрд▓рддрд╛ рд╣реНрдпрд╛рдиреНрдбрд▓рд┐рдВрдЧ рд░ рд╡рд┐рдлрд▓рддрд╛рд╣рд░реВрдмрд╛рдЯ рд░рд┐рдХрднрд░реА
@CircuitBreaker(delay=500 // milliseconds
failureRatio = .75,
requestVolumeThreshold = 20,
successThreshold = 5)
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
makeRemoteCall(); //...
}
@рдкрдЫрд╛рдбреА рд╣рдЯ
рдЕрд╕рдлрд▓ рднрдПрдХреЛ рдЕрд╡рд╕реНрдерд╛рдорд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рддрд░реНрдХ рдХрд▓ рдЧрд░реНрджреИ
@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(); //...
}
рдЬрд╛рдБрдЪ рд╕реЗрд╡рд╛рд╣рд░реВ (рд╕реЗрд╡рд╛ рд╕реНрд╡рд╛рд╕реНрдереНрдп)
Kubernetes рдкреНрд▓реЗрдЯрдлрд░реНрдорд╣рд░реВрд▓реЗ рд╡рд┐рд╢реЗрд╖ рд╕реЗрд╡рд╛рд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдХрдиреНрдЯреЗрдирд░рд╣рд░реВрдХреЛ рд╕реНрд╡рд╛рд╕реНрдереНрдп рдирд┐рдЧрд░рд╛рдиреА рдЧрд░реНрджрдЫред рдЕрдиреНрддрд░реНрдирд┐рд╣рд┐рдд рдкреНрд▓реЗрдЯрдлрд░реНрдорд▓рд╛рдИ рд╕реЗрд╡рд╛рд╣рд░реВ рдЕрдиреБрдЧрдорди рдЧрд░реНрди рдЕрдиреБрдорддрд┐ рджрд┐рди, рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛ рдХрд╕реНрдЯрдо рд╣реЗрд▓реНрде рдЗрдиреНрдбрд┐рдХреЗрдЯрд░ рд░ рд╡рд╕рдиреНрдд рдмреБрдЯ рдПрдХреНрдЪреБрдПрдЯрд░ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫрдиреНред рдХреНрд╡рд╛рд░реНрдХрд╕рдорд╛, рдпреЛ рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд╣реЗрд▓реНрдердХреЛ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ, рдЬрд╕рд▓реЗ рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд░реВрдкрдорд╛ рдЬреАрд╡рдиреНрддрддрд╛ рдЬрд╛рдБрдЪ рдЧрд░реНрдЫ, рддрд░ рдПрдХреИрд╕рд╛рде рдЬреАрд╡рдиреНрддрддрд╛ рд░ рддрдпрд╛рд░реА рдЬрд╛рдБрдЪ рдЧрд░реНрди рдХрдиреНрдлрд┐рдЧрд░ рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫред рд╕рдорд░реНрдерд┐рдд рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд╣реЗрд▓реНрде API рд╣рд░реВ рдХрд╕рд░реА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рднрдиреНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рддрд╛рд▓рд┐рдХрд╛ 6 рдорд╛ рдкреНрд░рджрд╛рди рдЧрд░рд┐рдПрдХреЛ рдЫ, рд░ рдердк рдЬрд╛рдирдХрд╛рд░реА рдХреНрд╡рд╛рд░реНрдХрд╕ рдореНрдпрд╛рдиреБрдЕрд▓рдорд╛ рдкреНрд░рджрд╛рди рдЧрд░рд┐рдПрдХреЛ рдЫред
рддрд╛рд▓рд┐рдХрд╛ рем: рд╕рдорд░реНрдерд┐рдд рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд╣реЗрд▓реНрде API рдХреЛ рдкреНрд░рдпреЛрдЧрдХрд╛ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рдорд╛рдЗрдХреНрд░реЛ рдкреНрд░реЛрдлрд╛рдЗрд▓ рд╕реНрд╡рд╛рд╕реНрдереНрдп рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рд╡рд┐рд╡рд░рдг
рдЙрджрд╛рд╣рд░рдг
@рдЬреАрд╡рд┐рддрддрд╛
рдкреНрд▓реЗрдЯрдлрд░реНрдо рд░рд┐рдмреБрдЯ рдЕрд╕рдлрд▓ рдХрдиреНрдЯреЗрдирд░реАрдХреГрдд рдЕрдиреБрдкреНрд░рдпреЛрдЧрд╣рд░реВ
рдЕрдиреНрддрд┐рдо рдмрд┐рдиреНрджреБ:
рд╣реЛрд╕реНрдЯ: 8080/рд╕реНрд╡рд╛рд╕реНрдереНрдп/рд▓рд╛рдЗрдн
@Liveness
public class MyHC implements HealthCheck {
public HealthCheckResponse call() {
...
return HealthCheckResponse
.named("myHCProbe")
.status(ready ? true:false)
.withData("mydata", data)
.build();
}
@рддрддреНрдкрд░рддрд╛
рдкреНрд▓реЗрдЯрдлрд░реНрдорд▓реЗ рдХрдиреНрдЯреЗрдирд░реАрдХреГрдд рдЕрдиреБрдкреНрд░рдпреЛрдЧрд╣рд░реВрдорд╛ рдЯреНрд░рд╛рдлрд┐рдХ рдкрдард╛рдЙрдиреЗ рдЫреИрди рдпрджрд┐ рдпреЛ рддрдпрд╛рд░ рдЫреИрди рднрдиреЗ
рдЕрдиреНрддрд┐рдо рдмрд┐рдиреНрджреБ:
рд╣реЛрд╕реНрдЯ: 8080/рд╕реНрд╡рд╛рд╕реНрдереНрдп/рддрдпрд╛рд░
@Readiness
public class MyHC implements HealthCheck {
public HealthCheckResponse call() {
...
return HealthCheckResponse
.named("myHCProbe")
.status(live ? true:false)
.withData("mydata", data)
.build();
}
рдореЗрдЯреНрд░рд┐рдХреНрд╕
рдЕрдиреБрдкреНрд░рдпреЛрдЧрд╣рд░реВрд▓реЗ рдпрд╛ рдд рдкрд░рд┐рдЪрд╛рд▓рди рдЙрджреНрджреЗрд╢реНрдпрд╣рд░реВ (рдХрд╛рд░реНрдпрд╕рдореНрдкрд╛рджрди SLAs рдЕрдиреБрдЧрдорди рдЧрд░реНрди) рд╡рд╛ рдЧреИрд░-рд╕рдЮреНрдЪрд╛рд▓рди рдЙрджреНрджреЗрд╢реНрдпрд╣рд░реВ (рд╡реНрдпрд╛рдкрд╛рд░ SLAs) рдХреЛ рд▓рд╛рдЧрд┐ рдореЗрдЯреНрд░рд┐рдХрд╣рд░реВ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫред рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рд╡рд╕рдиреНрдд рдмреБрдЯ рдПрдХреНрдЪреБрдПрдЯрд░ рд░ рдорд╛рдЗрдХреНрд░реЛрдорд┐рдЯрд░ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдореЗрдЯреНрд░рд┐рдХрд╣рд░реВ рдкреНрд░рджрд╛рди рдЧрд░реНрдЫрдиреНред рдмрджрд▓рд╛рдорд╛, рдХреНрд╡рд╛рд░реНрдХрд╕рд▓реЗ рдЖрдзрд╛рд░рднреВрдд рдореЗрдЯреНрд░рд┐рдХреНрд╕ (JVM рд░ рдЕрдкрд░реЗрдЯрд┐рдЩ рд╕рд┐рд╕реНрдЯрдо), рд╡рд┐рдХреНрд░реЗрддрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕ (рдХреНрд╡рд╛рд░реНрдХрд╕), рд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдкреНрд░рджрд╛рди рдЧрд░реНрди рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрдЫред рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдЯреНрд░рд┐рдХреНрд╕рд▓рд╛рдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирд▓реЗ JSON рд░ OpenMetrics (Prometheus) рдЖрдЙрдЯрдкреБрдЯ рдврд╛рдБрдЪрд╛рд╣рд░реВрд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫред рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдЯреНрд░рд┐рдХреНрд╕ API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рддрд╛рд▓рд┐рдХрд╛ 7 рдорд╛ рджрд┐рдЗрдПрдХреЛ рдЫред
╨Т
рддрд╛рд▓рд┐рдХрд╛ рен. рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдЯреНрд░рд┐рдХреНрд╕ API рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рд╡рд┐рд╡рд░рдг
рдЙрджрд╛рд╣рд░рдг
@ рдЧрдгрдирд╛ рдЧрд░рд┐рдПрдХреЛ
рдПрдХ рдХрд╛рдЙрдиреНрдЯрд░ рдХрд╛рдЙрдиреНрдЯрд░рд▓рд╛рдИ рдЬрдирд╛рдЙрдБрдЫ рдЬрд╕рд▓реЗ рдПрдиреЛрдЯреЗрдЯреЗрдб рд╡рд╕реНрддреБрд▓рд╛рдИ рдХрд▓ рдЧрд░рд┐рдПрдХреЛ рд╕рдВрдЦреНрдпрд╛ рдЧрдгрдирд╛ рдЧрд░реНрджрдЫ
@Counted(name = "fallbackCounter",
displayName = "Fallback Counter",
description = "Fallback Counter")
public String salutationFallback() {
return fallbackSalutation;
}
@ConcurrentGauge
рдПрдиреЛрдЯреЗрдЯ рд╡рд╕реНрддреБрдорд╛ рд╕рдорд╡рд░реНрддреА рдХрд▓рд╣рд░реВрдХреЛ рд╕рдЩреНрдЦреНрдпрд╛ рдЧрдгрдирд╛ рдЧрд░реНрдиреЗ рдЧреЗрдЬрд▓рд╛рдИ рдЬрдирд╛рдЙрдБрдЫ
@ConcurrentGuage(
name = "fallbackConcurrentGauge",
displayName="Fallback Concurrent",
description="Fallback Concurrent")
public String salutationFallback() {
return fallbackSalutation;
}
@ рдЧреЗрдЬ
рдПрдХ рдЧреЗрдЬ рд╕реЗрдиреНрд╕рд░рд▓рд╛рдИ рдЬрдирд╛рдЙрдБрдЫ рдЬрд╕рд▓реЗ рдПрдиреЛрдЯреЗрдЯ рд╡рд╕реНрддреБрдХреЛ рдореВрд▓реНрдп рдорд╛рдкрди рдЧрд░реНрджрдЫ
@Metered(name = "FallbackGauge",
displayName="Fallback Gauge",
description="Fallback frequency")
public String salutationFallback() {
return fallbackSalutation;
}
@Metered
рдПрдиреЛрдЯреЗрдЯ рд╡рд╕реНрддреБрдХреЛ рдХрд▓ рдлреНрд░рд┐рдХреНрд╡реЗрдиреНрд╕реА рдЕрдиреБрдЧрдорди рдЧрд░реНрдиреЗ рдорд┐рдЯрд░ рд╕реЗрдиреНрд╕рд░рд▓рд╛рдИ рдЬрдирд╛рдЙрдБрдЫ
@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;
}
рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдЕрдиреНрддреНрдп рдмрд┐рдиреНрджреБрд╣рд░реВ
рдЖрд╡реЗрджрди рдореЗрдЯреНрд░рд┐рдХреНрд╕
рдЖрдзрд╛рд░рднреВрдд рдореЗрдЯреНрд░рд┐рдХреНрд╕
рд╡рд┐рдХреНрд░реЗрддрд╛ рдореЗрдЯреНрд░рд┐рдХреНрд╕
рд╕рдмреИ рдореЗрдЯреНрд░рд┐рдХреНрд╕
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд░реЗрд╕реНрдЯ рдХреНрд▓рд╛рдЗрдиреНрдЯ
Microservices рд▓реЗ рдкреНрд░рд╛рдпрдГ RESTful Endpoints рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫ рдЬрд╕рдорд╛ рд╕рдореНрдмрдиреНрдзрд┐рдд рдЧреНрд░рд╛рд╣рдХ API рд╣рд░реВ рдХрд╛рдо рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рд╣реБрдиреНрдЫред RESTful endpoints рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди, Spring рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛ RestTemplate рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫрдиреНред рдХреНрд╡рд╛рд░реНрдХрд╕рд▓реЗ рдпреЛ рд╕рдорд╕реНрдпрд╛ рд╕рдорд╛рдзрд╛рди рдЧрд░реНрди рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд░реЗрд╕реНрдЯ рдХреНрд▓рд╛рдЗрдиреНрдЯ рдПрдкреАрдЖрдИрд╣рд░реВ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫ, рдЬрд╕рдХреЛ рдкреНрд░рдпреЛрдЧрдХрд╛ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рддрд╛рд▓рд┐рдХрд╛ рео рдорд╛ рджрд┐рдЗрдПрдХреЛ рдЫред
╨Т
рддрд╛рд▓рд┐рдХрд╛ рео. рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд░реЗрд╕реНрдЯ рдХреНрд▓рд╛рдЗрдиреНрдЯ API рд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВред
рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рд░реЗрд╕реНрдЯ рдХреНрд▓рд╛рдЗрдиреНрдЯ рд╕реБрд╡рд┐рдзрд╛рд╣рд░реВ
рд╡рд┐рд╡рд░рдг
рдЙрджрд╛рд╣рд░рдг
@RegisterRestClient
REST рдХреНрд▓рд╛рдЗрдиреНрдЯрдХреЛ рд░реВрдкрдорд╛ рдЯрд╛рдЗрдк рдЧрд░рд┐рдПрдХреЛ рдЬрд╛рднрд╛ рдЗрдиреНрдЯрд░рдлреЗрд╕ рджрд░реНрддрд╛ рдЧрд░реНрджрдЫ
@RegisterRestClient
@Path("/")
public interface MyRestClient {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getSalutation();
}
@RestClient
рдЯрд╛рдЗрдк рдЧрд░рд┐рдПрдХреЛ REST рдХреНрд▓рд╛рдЗрдиреНрдЯ рдЗрдиреНрдЯрд░рдлреЗрд╕рдХреЛ рдЙрджрд╛рд╣рд░рдгрдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирд▓рд╛рдИ рдЪрд┐рдиреНрд╣ рд▓рдЧрд╛рдЙрдБрдЫ
@Autowired // or @Inject
@RestClient
MyRestClient restClient;
рдирд┐рдордиреНрддреНрд░рдгрд╛
REST рдЕрдиреНрддреНрдп рдмрд┐рдиреНрджреБрд▓рд╛рдИ рдХрд▓ рдЧрд░реНрджрдЫ
System.out.println(
restClient.getSalutation());
mp-rest/url
REST рдЕрдиреНрддреНрдп рдмрд┐рдиреНрджреБ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЧрд░реНрджрдЫ
application.properties:
org.example.MyRestClient/mp-rest/url=
http://localhost:8081/myendpoint
рдкрд░рд┐рдгрд╛рдорд╣рд░реВ
рдпрд╕ рдмреНрд▓рдЧрдорд╛, рдореБрдЦреНрдп рд░реВрдкрдорд╛ рд╡рд╕рдиреНрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓рд╛рдИ рд▓рдХреНрд╖рд┐рдд рдЧрд░реНрджреИ, рд╣рд╛рдореАрд▓реЗ рдХреНрд╡рд╛рд░реНрдХрд╕рдорд╛ рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдкреАрдЖрдИрд╣рд░реВрд╕рдБрдЧ рдЬрд╛рднрд╛ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрднрд┐рд╕реЗрд╕рд╣рд░реВ рд╡рд┐рдХрд╛рд╕ рдЧрд░реНрди рд░ рддреНрдпрд╕рдкрдЫрд┐ рддрд┐рдиреАрд╣рд░реВрд▓рд╛рдИ рд╕рдпреМрдВ рдореЗрдЧрд╛рдмрд╛рдЗрдЯ RAM рдмрдЪрдд рдЧрд░реНрдиреЗ рд░ рддреНрдпрд╕рдкрдЫрд┐ рд╕реБрд░реБ рд╣реБрдиреЗ рдиреЗрдЯрд┐рдн рдмрд╛рдЗрдирд░реА рдХреЛрдбрдорд╛ рдХрдореНрдкрд╛рдЗрд▓ рдЧрд░реНрдиреЗ рддрд░рд┐рдХрд╛рдорд╛ рджреНрд░реБрдд рд░реВрдкрдорд╛ рд╣реЗрд░реЗрдХрд╛ рдЫреМрдВред рдорд┐рд▓рд┐рд╕реЗрдХреЗрдиреНрдбрдХреЛ рдХреБрд░рд╛ред
рддрдкрд╛рдИрдВрд▓реЗ рдкрд╣рд┐рд▓реЗ рдиреИ рдмреБрдЭреНрдиреБрднрдПрдХреЛ рд░реВрдкрдорд╛, рд╡рд╕рдиреНрдд рд░ рдорд╛рдЗрдХреНрд░реЛрдкреНрд░реЛрдлрд╛рдЗрд▓ API рдХреЛ рд▓рд╛рдЧрд┐ рд╕рдорд░реНрдердирдХреЛ рдмрд╛рд░реЗрдорд╛ рдердк рдЬрд╛рдирдХрд╛рд░реА, рд╕рд╛рдереИ рдЕрдиреНрдп рдзреЗрд░реИ рдЙрдкрдпреЛрдЧреА рдЬрд╛рдирдХрд╛рд░реА, рдорд╛ рдкрд╛рдЙрди рд╕рдХрд┐рдиреНрдЫред
рд╕реНрд░реЛрдд: www.habr.com