{"id":291305,"date":"2018-10-24T18:10:02","date_gmt":"2018-10-24T14:10:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=291305"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2018-10-24T14:10:02","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=291305","title":{"rendered":"\u041f\u0440\u043e\u0431\u0443\u0435\u043c Micronaut \u0438\u043b\u0438 \u0414\u043e\u0440\u043e\u0433\u0430\u044f, \u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a"},"content":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<h2 id=\"probuem-micronaut-ili-dorogaya-ya-umenshil-freymvork\">\u041f\u0440\u043e\u0431\u0443\u0435\u043c Micronaut \u0438\u043b\u0438 \u0414\u043e\u0440\u043e\u0433\u0430\u044f, \u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a<\/h2>\n<p>  <\/p>\n<p>\u041f\u0440\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a micronaut \u044f \u043c\u0435\u043b\u044c\u043a\u043e\u043c \u0432\u044b\u0447\u0438\u0442\u0430\u043b \u0438\u0437 \u0434\u0430\u0439\u0434\u0436\u0435\u0441\u0442 \u0440\u0430\u0441\u0441\u044b\u043b\u043e\u043a. \u0417\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0441\u044f, \u0447\u0442\u043e \u0437\u0430 \u0437\u0432\u0435\u0440\u044c \u0442\u0430\u043a\u043e\u0439. \u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0432\u0435\u0437 \u043d\u0430\u043f\u0438\u0447\u043a\u0430\u043d\u043d\u043e\u043c\u0443 \u0432\u0441\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c Spring. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/eu\/iq\/eq\/euiqeqqehjcvuto1psel_ajypw4.jpeg\" alt=\"Micronaut\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u0432\u043e\u0441\u0445\u0438\u0449\u0430\u044f \u0433\u0440\u044f\u0434\u0443\u0449\u0443\u044e \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0433\u0434\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c micronaut \u0432 \u0432\u0430\u0448\u0438\u0445 \u044d\u0442\u0438\u0445 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u044f \u0440\u0435\u0448\u0438\u043b \u0445\u043e\u0442\u044c \u0440\u0430\u0437 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u0440\u0438\u0439\u0442\u0438 \u0445\u043e\u0442\u044c \u0441 \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0432 \u0433\u043e\u043b\u043e\u0432\u0435, \u0441 \u043d\u0435\u043a\u0438\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432. \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435. \u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043b\u0430\u0431\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 pet-project \u0437\u0430 \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0432\u0435\u0447\u0435\u0440\u043e\u0432 (\u043a\u0430\u043a \u043f\u043e\u0439\u0434\u0451\u0442). \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432\u0441\u0435\u0445 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<blockquote><p>Micronaut \u2014 \u044d\u0442\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 JVM, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0440\u0438 \u044f\u0437\u044b\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438: Java, Kotlin, Groovy. \u041e\u043d \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439 OCI, \u0442\u043e\u0439 \u0436\u0435 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439, \u0447\u0442\u043e \u043f\u043e\u0434\u0430\u0440\u0438\u043b\u0430 \u043d\u0430\u043c Grails. \u0418\u043c\u0435\u0435\u0442 \u0442\u0443\u043b\u0438\u043d\u0433 \u0432 \u0432\u0438\u0434\u0435 cli-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0431\u043e\u0440 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a (\u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 reactive- http \u0438 database \u043a\u043b\u0438\u0435\u043d\u0442\u044b)<\/p>\n<p>  \u0415\u0441\u0442\u044c DI, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u0438\u0434\u0435\u0438 Spring, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044f \u0440\u044f\u0434 \u0441\u0432\u043e\u0438\u0445 \u0444\u0438\u0448\u0435\u043a \u2014 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0449\u0438\u043d\u0430, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 AWS Lambda, Client Side Load Balancing.<\/p><\/blockquote>\n<p><em>\u0418\u0434\u0435\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/em> \u043e\u0434\u0438\u043d \u043c\u043e\u0439 \u0434\u0440\u0443\u0433 \u0432 \u0441\u0432\u043e\u0451 \u0432\u0440\u0435\u043c\u044f \u0441 \u0434\u0443\u0440\u0443 \u043d\u0430\u043a\u0443\u043f\u0438\u043b \u0441 \u043f\u043e\u043b\u0434\u044e\u0436\u0438\u043d\u044b \u0432\u0441\u044f\u043a\u0438\u0445 \u0440\u0430\u0437\u043d\u043e\u043c\u0430\u0441\u0442\u043d\u044b\u0445 \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442, \u0432\u043b\u043e\u0436\u0438\u0432 \u0442\u0443\u0434\u0430 \u043d\u0435\u043f\u0440\u043e\u043f\u0438\u0442\u044b\u0435 \u043e\u0442\u043f\u0443\u0441\u043a\u043d\u044b\u0435 \u0438 \u0437\u0430\u043d\u0430\u0447\u043a\u0443 \u0438\u0437 \u0437\u0438\u043c\u043d\u0435\u0439 \u043a\u0443\u0440\u0442\u043a\u0438. \u0412\u0441\u0435 \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0432\u043e\u043b\u0430\u0442\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0439 \u044d\u0442\u043e \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u043d\u043e\u0439 \u0441\u0443\u0431\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u0434\u0438\u043a\u0430\u044f, \u0430 \u0441\u0430\u043c\u0430 \u0442\u0435\u043c\u0430 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u0430\u044f, \u0434\u0440\u0443\u0433 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0431\u0435\u0440\u0435\u0447\u044c \u0441\u0432\u043e\u0438 \u043d\u0435\u0440\u0432\u044b \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0437\u0430\u0431\u0438\u0442\u044c \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u0435\u0433\u043e \u201c\u0430\u043a\u0442\u0438\u0432\u0430\u043c\u0438\u201d. \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0432\u0441\u0451 \u0442\u0430\u043a\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c, \u0430 \u0447\u0442\u043e \u0436\u0435 \u0442\u0430\u043c \u0441 \u044d\u0442\u0438\u043c \u0432\u0441\u0435\u043c, \u0432\u0434\u0440\u0443\u0433 \u0443\u0436\u0435 \u0431\u043e\u0433\u0430\u0442. \u0422\u0430\u043a \u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0438\u0434\u0435\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 (dashboard, \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 Grafana \u0438\u043b\u0438 \u0447\u0442\u043e \u043f\u043e\u043f\u0440\u043e\u0449\u0435), \u043d\u0435\u043a\u043e\u0439 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0438 \u0441 \u0441\u0443\u0445\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u0451 \u044d\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u0432 \u043d\u0435\u043a\u043e\u0439 \u0444\u0438\u0430\u0442\u043d\u043e\u0439 \u0432\u0430\u043b\u044e\u0442\u0435 (USD, RUR).<\/p>\n<p>  <\/p>\n<h3 id=\"disclaimers\">Disclaimers<\/h3>\n<p>  <\/p>\n<ol>\n<li>\u0426\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u0437\u0430 \u0431\u043e\u0440\u0442\u043e\u043c, \u043d\u0430\u043c \u0432\u0441\u0435\u0433\u043e-\u043b\u0438\u0448\u044c \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u044b\u0442\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 \u0447\u0435\u043c-\u0442\u043e \u043f\u043e\u0445\u0438\u0442\u0440\u0435\u0435 HelloWorld.<\/li>\n<li>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0440\u0430\u0441\u0447\u0435\u0442\u0430, \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043f\u043e\u0433\u0440\u0435\u0448\u043d\u043e\u0441\u0442\u0438 \u0438 \u0442.\u0434. (\u043f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0439 \u043c\u0435\u0440\u0435 \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0439 \u0444\u0430\u0437\u044b \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430), \u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u0430 \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436 \u0434\u043b\u044f \u0432\u044b\u0442\u044f\u0433\u0438\u0432\u0430\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u201c\u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0439\u201d \u043a\u0440\u0438\u043f\u0442\u043e\u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u0434\u0440\u0443\u0433\u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430 \u0441\u043a\u043e\u0431\u043a\u0430\u043c\u0438 \u0438 \u043d\u0435 \u043f\u043e\u0434\u043b\u0435\u0436\u0438\u0442 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u044e \u0438\u043b\u0438 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0435.<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0412\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441 (\u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437\u0432\u043d\u0435, \u043f\u043e http)<\/li>\n<li>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0441\u043e \u0441\u0432\u043e\u0434\u043a\u043e\u0439 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442<\/li>\n<li>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c (\u0432\u044b\u0431\u0435\u0440\u0435\u043c JSON \u0444\u043e\u0440\u043c\u0430\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f). \u041d\u0435\u043a\u0438\u0439 REST API \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0435\u0433\u043e, \u0442.\u0435. 2 API: \u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\/\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u2013 POST, \u043d\u0430 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u2013 GET. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f \u2013 \u044d\u0442\u043e \u043f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0430 \u0432\u0438\u0434\u0430<br \/> \n<pre><code>BTC \u2013 \u043a\u0443\u043f\u0438\u043b 0.00005 \u0435\u0434. XEM \u2013 \u043a\u0443\u043f\u0438\u043b 4.5 \u0435\u0434. ...<\/code><\/pre>\n<\/li>\n<li>\u0414\u0430\u043d\u043d\u044b\u0435 \u0431\u0435\u0440\u0435\u043c \u0438\u0437 \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436 \u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442 (\u0434\u043b\u044f \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442)<\/li>\n<li>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0440\u0430\u0441\u0447\u0451\u0442\u0430 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/95\/ai\/fn\/95aifnv4r6bngnaeqrb9tlu2hfy.png\" alt=\"\u0424\u043e\u0440\u043c\u0443\u043b\u044b \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f\"\/>  <\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u0432\u0441\u0451 \u0442\u043e, \u0447\u0442\u043e \u043f\u043e\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u043f\u0443\u043d\u043a\u0442\u0435 5 \u2014 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043f\u043e\u0440\u043e\u0432 \u0438 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u0439, \u043d\u043e \u043f\u0443\u0441\u0442\u044c \u0431\u0443\u0434\u0435\u0442, \u0447\u0442\u043e \u0431\u0438\u0437\u043d\u0435\u0441 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u0442\u0430\u043a.<\/p>\n<p>  <\/p>\n<h2 id=\"start-proekta\">\u0421\u0442\u0430\u0440\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0438\u0434\u0435\u043c \u043d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043d\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c. \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 sdkman. \u0428\u0442\u0443\u043a\u0430, \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u044e\u0449\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 micronaut (\u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u2013 Grails).  <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/af\/rd\/3z\/afrd3zhw_oodv3s1kroj5vx6bgu.png\" alt=\"\u0422\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 SDK\"\/><\/p>\n<p>  \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0440\u0435\u043c\u0430\u0440\u043a\u0430: \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0439, \u0442\u043e \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u0431\u043e\u0440\u0449\u0438\u043a gradle. \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043f\u0430\u043f\u043a\u0443, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043d\u043e\u0432\u043e, \u043d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0441 \u043a\u043b\u044e\u0447\u043e\u043c:   <\/p>\n<pre><code>mn create-app com.room606.cryptonaut -b=maven<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0442\u0430\u043a\u0436\u0435, \u0447\u0442\u043e sdkman \u043a\u0430\u043a \u0438 Spring Tool Suite \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0432\u0430\u043c \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0437\u0430\u0434\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u201c\u043a\u0443\u0431\u0438\u043a\u0438\u201d \u0432\u044b \u0436\u0435\u043b\u0430\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435. \u0421 \u044d\u0442\u0438\u043c \u044f \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043b, \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043b \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u043c \u043f\u0440\u0435\u0441\u0435\u0442\u043e\u043c.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 Intellij Idea \u0438 \u043b\u044e\u0431\u0443\u0435\u043c\u0441\u044f \u0442\u0435\u043c \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442\u043e\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438 \u0431\u043e\u043b\u0432\u0430\u043d\u043e\u043a, \u0447\u0442\u043e \u043d\u0430\u0441 \u0441\u043d\u0430\u0431\u0434\u0438\u043b \u0432\u0438\u0437\u0430\u0440\u0434 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f micronaut \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/8n\/oh\/ko\/8nohkocdymxsv2ctnkqlvnvr1x4.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0433\u043e\u043b\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430\"\/><\/p>\n<p>  \u0413\u043b\u0430\u0437 \u0446\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430 \u0444\u0430\u0439\u043b Dockerfile  <\/p>\n<pre><code>FROM openjdk:8u171-alpine3.7 RUN apk --no-cache add curl COPY target\/cryptonaut*.jar cryptonaut.jar CMD java ${JAVA_OPTS} -jar cryptonaut.jar<\/code><\/pre>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u0436\u0435, \u044d\u0442\u043e \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u043e \u0438 \u043f\u043e\u0445\u0432\u0430\u043b\u044c\u043d\u043e. \u041d\u0430\u0441 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0441\u043d\u0430\u0431\u0434\u0438\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Prod\/INT\/QA\/whatever \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0417\u0430 \u044d\u0442\u043e \u043c\u044b\u0441\u043b\u0435\u043d\u043d\u044b\u0439 \u043f\u043b\u044e\u0441\u0438\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443.<\/p>\n<p>  <\/p>\n<p>\u0414\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438\u0448\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 Maven-\u043e\u043c, \u0434\u0430\u043b\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c Docker \u043e\u0431\u0440\u0430\u0437 \u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0432\u0430\u0448\u0435 Docker registry \u0438\u043b\u0438 \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u043d\u0430\u0440\u043d\u0438\u043a \u043e\u0431\u0440\u0430\u0437\u0430 \u043a\u0430\u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0432 \u0432\u0430\u0448\u0443 CI-\u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0442\u0443\u0442 \u0443\u0436 \u043a\u0430\u043a \u0432\u0430\u043c \u0443\u0433\u043e\u0434\u043d\u043e.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u043d\u0430\u0441 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 \u0431\u043e\u043b\u0432\u0430\u043d\u043a\u0443 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0430\u043d\u0430\u043b\u043e\u0433 application.properties \u0432 Spring), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0444\u0438\u0433 \u0444\u0430\u0439\u043b\u043e\u043c \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 logback. \u041a\u0440\u0443\u0442\u043e!<\/p>\n<p>  <\/p>\n<p>\u0418\u0434\u0435\u043c \u0432\u043e \u0432\u0445\u043e\u0434\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u0443\u0447\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441. \u0412\u0438\u0434\u0438\u043c \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u0434\u043e \u0431\u043e\u043b\u0438 \u0437\u043d\u0430\u043a\u043e\u043c\u0443\u044e \u043d\u0430\u043c \u043f\u043e Spring Boot. \u0417\u0434\u0435\u0441\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u043a\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0442\u043e\u0436\u0435 \u043d\u0435 \u0441\u0442\u0430\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043c\u0443\u0434\u0440\u0438\u0442\u044c \u0438 \u0432\u044b\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c. <\/p>\n<p>  <\/p>\n<pre><code>public static void main(String[] args) throws IOException {     Micronaut.run(Application.class); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u0435 \u0441\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u043e Spring-\u0443.<\/p>\n<p>  <\/p>\n<pre><code>public static void main(String[] args) {     SpringApplication.run(App<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422.\u0435. \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u044b\u043c\u0430\u0435\u043c IoC-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0431\u0438\u043d\u0430\u043c\u0438, \u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u043e \u043c\u0435\u0440\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b. \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0431\u0435\u0436\u0430\u0432 \u043f\u043e \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u043d\u0435\u0441\u043f\u0435\u0448\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443. <\/p>\n<p>  <\/p>\n<p><em>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f:<\/em><\/p>\n<p>  <\/p>\n<ol>\n<li>\u041c\u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<\/li>\n<li>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 REST API.<\/li>\n<li>\u0421\u043b\u043e\u0439 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (Database client \u043b\u0438\u0431\u043e ORM \u043b\u0438\u0431\u043e \u0435\u0449\u0451 \u0447\u0442\u043e-\u0442\u043e)<\/li>\n<li>\u041a\u043e\u0434 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0431\u043c\u0435\u043d\u0430 \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442. \u0422.\u0435. \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0434\u043b\u044f 3rd party c\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0412 Spring \u043d\u0430 \u044d\u0442\u0443 \u0440\u043e\u043b\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b\u0438 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 \u043d\u0430\u043c RestTemplate.<\/li>\n<li>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0433\u0438\u0431\u043a\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0441\u0442\u0430\u0440\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u0447\u0442\u043e \u0438 \u043a\u0430\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438)<\/li>\n<li>\u0422\u0435\u0441\u0442\u044b! \u0414\u0430, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e \u0438 \u0431\u0435\u0437 \u043e\u043f\u0430\u0441\u043a\u0438 \u0440\u0435\u0444\u0430\u0447\u0438\u0442\u044c \u043a\u043e\u0434 \u0438 \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u0432 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u0430\u0440\u043e\u0439<\/li>\n<li>\u041a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. \u042d\u0442\u043e \u043d\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435, \u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0434\u043b\u044f \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0435\u0441\u0442\u044c \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u0447\u043d\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0445\u043e\u0440\u043e\u0448\u0438\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c.<br \/>  \u0421\u043f\u043e\u0439\u043b\u0435\u0440: \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u043f\u043e\u0439\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u043b\u043e\u0445\u043e.<\/li>\n<\/ol>\n<p>  <\/p>\n<h3 id=\"modeli-predmetnoy-oblasti\">\u041c\u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0445\u0432\u0430\u0442\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439: \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442, \u043e\u0431\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430 \u043f\u0430\u0440\u044b \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442, \u0446\u0435\u043d\u044b \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u044b \u0432 \u0444\u0438\u0430\u0442\u043d\u043e\u0439 \u0432\u0430\u043b\u044e\u0442\u0435, \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u0430\u044f \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f.<\/p>\n<p>  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043a\u043e\u0434 \u043b\u0438\u0448\u044c \u043f\u0430\u0440\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/marazmatIK@bitbucket.org\/marazmatIK\/cryptonaut.git\">\u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>. \u0418 \u0434\u0430, \u044f \u043f\u043e\u043b\u0435\u043d\u0438\u043b\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0442\u044c <code>Lombok<\/code>.<\/p>\n<p>  <\/p>\n<pre><code>Portfolio.java  package com.room606.cryptonaut.domain;  import java.math.BigDecimal; import java.util.Collections; import java.util.Map; import java.util.TreeMap;  public class Portfolio {     private Map&lt;String, BigDecimal&gt; coins = Collections.emptyMap();     public Map&lt;String, BigDecimal&gt; getCoins() {         return new TreeMap&lt;&gt;(coins);     }     public void setCoins(Map&lt;String, BigDecimal&gt; coins) {         this.coins = coins;     }<\/code><\/pre>\n<p>  <\/p>\n<pre><code>FiatRate.java package com.room606.cryptonaut.domain;  import java.math.BigDecimal;  public class FiatRate {     private String base;     private String counter;     private BigDecimal value;     public FiatRate(String base, String counter, BigDecimal value) {         this.base = base;         this.counter = counter;         this.value = value;     }     public String getBase() {         return base;     }     public void setBase(String base) {         this.base = base;     }     public String getCounter() {         return counter;     }     public void setCounter(String counter) {         this.counter = counter;     }     public BigDecimal getValue() {         return value;     }     public void setValue(BigDecimal value) {         this.value = value;     } }<\/code><\/pre>\n<p>  <\/p>\n<pre><code>Price.java ... Prices.java (\u0430\u0433\u0440\u0435\u0433\u0430\u0442) ... Total.java ...<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"kontrollery\">\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<\/h3>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 API, \u0432\u044b\u0434\u0430\u044e\u0449\u0438\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442 \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0431\u0443\u043a\u0432\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u0434\u0430\u043c \u043c\u043e\u043d\u0435\u0442.<br \/>  \u0422.\u0435. <\/p>\n<p>  <\/p>\n<pre><code>GET \/cryptonaut\/restapi\/prices.json?coins=BTC&amp;coins=ETH&amp;fiatCurrency=RUR<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0434\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435: <\/p>\n<p>  <\/p>\n<pre><code>{&quot;prices&quot;:[{&quot;coin&quot;:&quot;BTC&quot;,&quot;value&quot;:407924.043300000000},{&quot;coin&quot;:&quot;ETH&quot;,&quot;value&quot;:13040.638266000000}],&quot;fiatCurrency&quot;:&quot;RUR&quot;}<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e <a href=\"https:\/\/docs.micronaut.io\/latest\/guide\/index.html#routing\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>, \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e \u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u0442\u0435 \u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0438 \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f <code>Spring<\/code>: <\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut.rest; import com.room606.cryptonaut.domain.Price; import com.room606.cryptonaut.domain.Prices; import com.room606.cryptonaut.markets.FiatExchangeRatesService; import com.room606.cryptonaut.markets.CryptoMarketDataService; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream;  @Controller(&quot;\/cryptonaut\/restapi\/&quot;) public class MarketDataController {     private final CryptoMarketDataService cryptoMarketDataService;     private final FiatExchangeRatesService fiatExchangeRatesService;      public MarketDataController(CryptoMarketDataService cryptoMarketDataService, FiatExchangeRatesService fiatExchangeRatesService) {         this.cryptoMarketDataService = cryptoMarketDataService;         this.fiatExchangeRatesService = fiatExchangeRatesService;     }      @Get(&quot;\/prices.json&quot;)     @Produces(MediaType.APPLICATION_JSON)     public Prices pricesAsJson(@QueryValue(&quot;coins&quot;) String[] coins, @QueryValue(&quot;fiatCurrency&quot;) String fiatCurrency) {         return getPrices(coins, fiatCurrency);     }      private Prices getPrices(String[] coins, String fiatCurrency) {         List&lt;Price&gt; prices = Stream.of(coins)                 .map(coin -&gt; new Price(coin, cryptoMarketDataService.getPrice(coin, fiatCurrency)))                 .collect(Collectors.toList());         return new Prices(prices, fiatCurrency);     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422.\u0435. \u043c\u044b \u0441\u043f\u043e\u043a\u043e\u0439\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u043d\u0430\u0448 <code>POJO<\/code>, \u0438 \u0431\u0435\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432\/\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432, \u0434\u0430\u0436\u0435 \u0431\u0435\u0437 \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439 Micronaut \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 http body \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u043c \u0441 <code>Spring<\/code> way:<\/p>\n<p>  <\/p>\n<pre><code>@RequestMapping(value  = &quot;\/prices.json&quot;,         method = RequestMethod.GET,         produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity&lt;Prices&gt; pricesAsJson(@RequestParam(&quot;userId&quot;) final String[] coins, @RequestParam(&quot;fiatCurrency&quot;) String fiatCurrency) {<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c, \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438 \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u043e, \u043e\u043d\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0442\u0430\u043a, \u043a\u0430\u043a \u043e\u0442 \u043d\u0438\u0445 \u043e\u0436\u0438\u0434\u0430\u043b\u043e\u0441\u044c, \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438. \u0418\u0445 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u043c. \u0414\u0432\u0438\u0433\u0430\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435. <\/p>\n<p>  <\/p>\n<h3 id=\"sloy-hraneniya-dannyh\">\u0421\u043b\u043e\u0439 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043b\u0438\u0448\u044c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u044e\u0437\u0435\u0440\u0430. \u0412\u043e\u043e\u0431\u0449\u0435, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u043e\u0434\u043d\u043e\u0433\u043e \u044e\u0437\u0435\u0440\u0430. \u041f\u0440\u043e\u0449\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u0443 \u043d\u0430\u0441 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043e \u0441\u0432\u043e\u0438\u043c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u0435\u043c \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442. \u0412\u043e\u0442 \u044d\u0442\u043e \u043a\u0440\u0443\u0442\u043e!<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c JPA, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0440\u044b\u0432\u043e\u0447\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438\u0437 \u0411\u0414 (\u0441\u0435\u043a\u0446\u0438\u044f \u201c12.1.5 Configuring Postgres\u201d). <code>JPA<\/code> \u0440\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0431\u0440\u043e\u0448\u0435\u043d\u043e \u0438 \u0431\u044b\u043b\u043e \u043e\u0442\u0434\u0430\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0440\u0443\u0447\u043d\u043e\u043c\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0438\u043c\u0438. \u0412 application.yml \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0411\u0414, (\u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0420\u0421\u0423\u0411\u0414 \u0431\u044b\u043b\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u0430 <code>Postgres<\/code>), \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code>postgres:     reactive:         client:             port: 5432             host: localhost             database: cryptonaut             user: crypto             password: r1ch13r1ch             maxSize: 5<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>postgres-reactive<\/code>. \u042d\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0411\u0414 \u043a\u0430\u043a \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043c\u0430\u043d\u0435\u0440\u0435, \u0442\u0430\u043a \u0438 \u0432 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439.<\/p>\n<p>  <\/p>\n<pre><code>&lt;dependency&gt;     &lt;groupId&gt;io.micronaut.configuration&lt;\/groupId&gt;     &lt;artifactId&gt;postgres-reactive&lt;\/artifactId&gt;     &lt;version&gt;1.0.0.M4&lt;\/version&gt;     &lt;scope&gt;compile&lt;\/scope&gt; &lt;\/dependency&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432 \u043f\u0430\u043f\u043a\u0443 <code>\/docker<\/code> \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0444\u0430\u0439\u043b\u0438\u043a <code>docker-compose.yml<\/code> \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u0443\u0434\u0430 \u0431\u044b\u043b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u0442 \u0411\u0414:<\/p>\n<p>  <\/p>\n<pre><code>db:   image: postgres:9.6   restart: always   environment:     POSTGRES_USER: crypto     POSTGRES_PASSWORD: r1ch13r1ch     POSTGRES_DB: cryptonaut   ports:         - 5432:5432   volumes:     - ${PWD}\/..\/db\/init_tables.sql:\/docker-entrypoint-initdb.d\/1.0.0_init_tables.sql<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0431\u0430\u0437\u044b \u0441 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u0437\u0430\u0442\u0435\u0439\u043b\u0438\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446:<\/p>\n<p>  <\/p>\n<pre><code>CREATE TABLE portfolio (     id                 serial CONSTRAINT coin_amt_primary_key PRIMARY KEY,     coin    varchar(16) NOT NULL UNIQUE,    amount  NUMERIC     NOT NULL );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043d\u0430\u043a\u0438\u0434\u0430\u0442\u044c \u043a\u043e\u0434, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041d\u0430\u0448 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut;  import com.room606.cryptonaut.domain.Portfolio; import java.math.BigDecimal; import java.util.Optional;  public interface PortfolioService {      Portfolio savePortfolio(Portfolio portfolio);     Portfolio loadPortfolio();     Optional&lt;BigDecimal&gt; calculateTotalValue(Portfolio portfolio, String fiatCurrency);  }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u044f \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 <code>Postgres reactive client<\/code> \u041d\u0430\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043a\u043b\u0430\u0441\u0441:<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut;  import com.room606.cryptonaut.domain.Portfolio; import com.room606.cryptonaut.markets.CryptoMarketDataService; import io.micronaut.context.annotation.Requires; import io.reactiverse.pgclient.Numeric; import io.reactiverse.reactivex.pgclient.*; import javax.inject.Inject; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors;  public class PortfolioServiceImpl implements PortfolioService {      private final PgPool pgPool;     ...      private static final String UPDATE_COIN_AMT = &quot;INSERT INTO portfolio (coin, amount) VALUES (?, ?) ON CONFLICT (coin) &quot; +             &quot;DO UPDATE SET amount = ?&quot;;     ...      public Portfolio savePortfolio(Portfolio portfolio) {         List&lt;Tuple&gt; records = portfolio.getCoins()                 .entrySet()                 .stream()                 .map(entry -&gt; Tuple.of(entry.getKey(), Numeric.create(entry.getValue()), Numeric.create(entry.getValue())))                 .collect(Collectors.toList());         pgPool.preparedBatch(UPDATE_COIN_AMT, records, pgRowSetAsyncResult -&gt; {            \/\/\u041d\u0435 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0442\u0430\u043a             pgRowSetAsyncResult.cause().printStackTrace();         });         return portfolio;     }     ... }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 API:<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut.rest;  import com.room606.cryptonaut.PortfolioService; import com.room606.cryptonaut.domain.Portfolio; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; import javax.inject.Inject;  @Controller(&quot;\/cryptonaut\/restapi\/&quot;)  public class ConfigController {      @Inject     private PortfolioService portfolioService;     @Post(&quot;\/portfolio&quot;)     @Produces(MediaType.APPLICATION_JSON)     @Consumes(MediaType.APPLICATION_JSON)     public Portfolio savePortfolio(@Body Portfolio portfolio) {         return portfolioService.savePortfolio(portfolio);     }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c <code>curl<\/code>-\u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<p>  <\/p>\n<pre><code>curl http:\/\/localhost:8080\/cryptonaut\/restapi\/portfolio -X POST -H &quot;Content-Type: application\/json&quot; --data '{&quot;coins&quot;: {&quot;XRP&quot;: &quot;35.5&quot;, &quot;LSK&quot;: &quot;5.03&quot;, &quot;XEM&quot;: &quot;16.23&quot;}}' -v<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0438\u2026 \u043b\u043e\u0432\u0438\u043c \u0432 \u043b\u043e\u0433\u0430\u0445 \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<p>  <\/p>\n<pre><code>io.reactiverse.pgclient.PgException: syntax error at or near &quot;,&quot;     at io.reactiverse.pgclient.impl.PrepareStatementCommand.handleErrorResponse(PrepareStatementCommand.java:74)     at io.reactiverse.pgclient.impl.codec.decoder.MessageDecoder.decodeError(MessageDecoder.java:250)     at io.reactiverse.pgclient.impl.codec.decoder.MessageDecoder.decodeMessage(MessageDecoder.java:139) ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0447\u0435\u0441\u0430\u0432 \u0440\u0435\u043f\u0443, \u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0435, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0433\u0443\u0433\u043b\u0438\u0442\u044c \u0434\u043e\u043a\u0443 \u043f\u043e \u0441\u0430\u043c\u043e\u0439 \u043b\u0438\u0431\u0435 <code>postgres-reactive<\/code>, \u0438 \u044d\u0442\u043e \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0414\u0435\u043b\u043e \u0431\u044b\u043b\u043e \u0432 placeholder-\u0430\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043a\u0438 \u0432\u0438\u0434\u0430 <code>$x ($1, $2, etc.)<\/code>. \u0418\u0442\u0430\u043a, \u0444\u0438\u043a\u0441 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0438 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<p>  <\/p>\n<pre><code>private static final String UPDATE_COIN_AMT = &quot;INSERT INTO portfolio (coin, amount) VALUES ($1, $2) ON CONFLICT (coin) &quot; +         &quot;DO UPDATE SET amount = $3&quot;;<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0442\u043e\u0442 \u0436\u0435 <code>REST<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u2026 \u0443\u0440\u0430. \u0414\u0430\u043d\u043d\u044b\u0435 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0447\u0442\u0435\u043d\u0438\u044e.<\/p>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u043c\u0438 \u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442 \u044e\u0437\u0435\u0440\u0430 \u0438\u0437 \u0411\u0414 \u0438 \u0441\u043c\u0430\u043f\u043f\u0438\u0442\u044c \u0438\u0445 \u043d\u0430 POJO-\u043e\u0431\u044a\u0435\u043a\u0442. \u0414\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u043c\u0435\u0442\u043e\u0434 pgPool.query(SELECT_COINS_AMTS, pgRowSetAsyncResult):<\/p>\n<p>  <\/p>\n<pre><code>public Portfolio loadPortfolio() {  Map&lt;String, BigDecimal&gt; coins = new HashMap&lt;&gt;();  pgPool.query(SELECT_COINS_AMTS, pgRowSetAsyncResult -&gt; {     if (pgRowSetAsyncResult.succeeded()) {         PgRowSet rows = pgRowSetAsyncResult.result();         PgIterator pgIterator = rows.iterator();         while (pgIterator.hasNext()) {             Row row = pgIterator.next();             coins.put(row.getString(&quot;coin&quot;), new BigDecimal(row.getFloat(&quot;amount&quot;)));         }     } else {         System.out.println(&quot;Failure: &quot; + pgRowSetAsyncResult.cause().getMessage());     } }); Portfolio portfolio = new Portfolio(); portfolio.setCoins(coins); return portfolio; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u044d\u0442\u043e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0437\u0430 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442:<\/p>\n<p>  <\/p>\n<pre><code>@Controller(&quot;\/cryptonaut\/restapi\/&quot;) public class ConfigController { ... @Get(&quot;\/portfolio&quot;) @Produces(MediaType.APPLICATION_JSON) public Portfolio loadPortfolio() {     return portfolioService.loadPortfolio(); } ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441. \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0440\u0432\u0430 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u044d\u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044c \u0445\u043e\u0442\u044c \u043a\u0430\u043a\u0438\u043c\u0438-\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u043c\u0438:<\/p>\n<p>  <\/p>\n<pre><code>curl http:\/\/localhost:8080\/cryptonaut\/restapi\/portfolio -X POST -H &quot;Content-Type: application\/json&quot; --data '{&quot;coins&quot;: {&quot;XRP&quot;: &quot;35.5&quot;, &quot;LSK&quot;: &quot;5.03&quot;, &quot;XEM&quot;: &quot;16.23&quot;}}' -v<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u0434, \u0447\u0438\u0442\u0430\u044e\u0449\u0438\u0439 \u0438\u0437 \u0411\u0414:<\/p>\n<p>  <\/p>\n<pre><code>curl http:\/\/localhost:8080\/cryptonaut\/restapi\/portfolio -v<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u2026 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u2026 \u043d\u0435\u0447\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0435:<\/p>\n<p>  <\/p>\n<pre><code>{&quot;coins&quot;:{}}<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e \u043d\u0435 \u0442\u0430\u043a \u043b\u0438? \u041f\u0435\u0440\u0435\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u0435\u0441\u044f\u0442\u044c \u0440\u0430\u0437, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c <code>curl<\/code> \u0437\u0430\u043f\u0440\u043e\u0441 \u0435\u0449\u0451 \u0440\u0430\u0437, \u0434\u0430\u0436\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0438\u0441. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u0441\u0451 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0434\u0438\u043a\u0438\u0439\u2026 \u041f\u0435\u0440\u0435\u0447\u0438\u0442\u0430\u0432 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443 \u043c\u0435\u0442\u043e\u0434\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0432, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 <code>Reactive Pg client<\/code>, \u0434\u043e\u0445\u043e\u0434\u0438\u043c \u0434\u043e \u043c\u044b\u0441\u043b\u0438, \u0447\u0442\u043e \u0432\u0435\u0434\u044c \u0442\u0430\u043a\u0438 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0434\u0435\u043b\u043e \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0449\u0438\u043d\u043e\u0439. \u0412\u0434\u0443\u043c\u0447\u0438\u0432\u044b\u0439 \u0434\u0435\u0431\u0430\u0433 \u044d\u0442\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b! \u0421\u0442\u043e\u0438\u043b\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u043e\u0434\u0435\u0431\u0430\u0436\u0438\u0442\u044c \u043a\u043e\u0434, \u043a\u0430\u043a \u0432\u0443\u0430-\u043b\u044f, \u043d\u0430\u043c \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u0441\u044c \u043d\u0435\u043f\u0443\u0441\u0442\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435!<\/p>\n<p>  <\/p>\n<p>\u0415\u0449\u0435 \u0440\u0430\u0437 \u043e\u0431\u0440\u0430\u0442\u0438\u0432\u0448\u0438\u0441\u044c \u043a \u0434\u043e\u043a\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0437\u0430\u043a\u0430\u0442\u0430\u0432 \u0440\u0443\u043a\u0430\u0432\u0430 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043c \u043a\u043e\u0434 \u043d\u0430 \u0438\u0441\u0442\u0438\u043d\u043d\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439, \u043d\u043e \u0437\u0430\u0442\u043e \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u0439: <\/p>\n<p>  <\/p>\n<pre><code>Map&lt;String, BigDecimal&gt; coins = new HashMap&lt;&gt;();         PgIterator pgIterator = pgPool.rxPreparedQuery(SELECT_COINS_AMTS).blockingGet().iterator();         while (pgIterator.hasNext()) {             Row row = pgIterator.next();             coins.put(row.getString(&quot;coin&quot;), new BigDecimal(row.getValue(&quot;amount&quot;).toString()));         }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c. \u042d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043a\u0443 \u0440\u0435\u0448\u0438\u043b\u0438, \u0434\u0432\u0438\u0433\u0430\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"pishem-klient-dlya-polucheniya-dannyh-po-rynkam\">\u041f\u0438\u0448\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0440\u044b\u043d\u043a\u0430\u043c<\/h3>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u043e\u0432. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0434\u0432\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436\u0430\u043c<\/li>\n<li>\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0440\u0443\u0447\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0437\u0430 \u043a\u0443\u0440\u0441\u043e\u043c \u0432\u0430\u043b\u044e\u0442. \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u043e, \u0447\u0442\u043e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 Micronaut.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438 \u0432\u0441\u0435 \u043d\u0435 \u0442\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e. \u041e\u0442\u043c\u0435\u0447\u0443 \u043b\u0438\u0448\u044c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0431\u0435\u0433\u043b\u043e\u043c \u043f\u043e\u0438\u0441\u043a\u0435 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d \u043f\u0440\u043e\u0435\u043a\u0442 <a href=\"https:\/\/github.com\/knowm\/XChange\">https:\/\/github.com\/knowm\/XChange<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u0430 \u043a\u0430\u043a \u0442\u0440\u0438 \u043a\u043e\u043f\u0435\u0439\u043a\u0438 \u2013 \u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0442\u0438\u043f\u0430 <code>Ticker<\/code> (\u043c\u043e\u0436\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c <code>bid<\/code>, <code>ask<\/code>, \u0432\u0441\u044f\u043a\u0438\u0435 open price, close price etc.), <code>CurrencyPair<\/code>, <code>Currency<\/code>. \u0414\u0430\u043b\u0435\u0435, \u0443\u0436\u0435 \u0441\u0430\u043c\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0435 \u0432 \u043a\u043e\u0434\u0435, \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432 \u0437\u0430\u0432\u043c\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436\u0435. \u0410 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043b\u0430\u0441\u0441, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u2013 <code>MarketDataService.java<\/code><\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u0441 \u0443\u0441\u0442\u0440\u043e\u0438\u0442 \u0442\u0430\u043a\u0430\u044f \u201c\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u201d:<\/p>\n<p>  <\/p>\n<pre><code>&lt;dependency&gt;   &lt;groupId&gt;org.knowm.xchange&lt;\/groupId&gt;   &lt;artifactId&gt;xchange-core&lt;\/artifactId&gt;   &lt;version&gt;4.3.10&lt;\/version&gt; &lt;\/dependency&gt; &lt;dependency&gt;   &lt;groupId&gt;org.knowm.xchange&lt;\/groupId&gt;   &lt;artifactId&gt;xchange-bittrex&lt;\/artifactId&gt;   &lt;version&gt;4.3.10&lt;\/version&gt; &lt;\/dependency&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043a\u043e\u0434, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0439 \u043a\u043b\u044e\u0447\u0435\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u2013 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u0435 \u0432 \u0444\u0438\u0430\u0442\u043d\u043e\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0438 (\u0441\u043c. \u0424\u043e\u0440\u043c\u0443\u043b\u044b, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432 \u0431\u043b\u043e\u043a\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439):<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut.markets; import com.room606.cryptonaut.exceptions.CryptonautException; import org.knowm.xchange.currency.Currency; import org.knowm.xchange.currency.CurrencyPair; import org.knowm.xchange.dto.marketdata.Ticker; import org.knowm.xchange.exceptions.CurrencyPairNotValidException; import org.knowm.xchange.service.marketdata.MarketDataService; import javax.inject.Inject; import javax.inject.Singleton; import java.io.IOException; import java.math.BigDecimal; @Singleton public class CryptoMarketDataService {     private final FiatExchangeRatesService fiatExchangeRatesService;     private final MarketDataService marketDataService;     @Inject     public CryptoMarketDataService(FiatExchangeRatesService fiatExchangeRatesService, MarketDataServiceFactory marketDataServiceFactory) {         this.fiatExchangeRatesService = fiatExchangeRatesService;         this.marketDataService = marketDataServiceFactory.getMarketDataService();     }     public BigDecimal getPrice(String coinCode, String fiatCurrencyCode) throws CryptonautException {         BigDecimal price = getPriceForBasicCurrency(coinCode, Currency.USD.getCurrencyCode());         if (Currency.USD.equals(new Currency(fiatCurrencyCode))) {             return price;         } else {             return price.multiply(fiatExchangeRatesService.getFiatPrice(Currency.USD.getCurrencyCode(), fiatCurrencyCode));         }     }     private BigDecimal getPriceForBasicCurrency(String coinCode, String fiatCurrencyCode) throws CryptonautException {         Ticker ticker = null;         try {             ticker = marketDataService.getTicker(new CurrencyPair(new Currency(coinCode), new Currency(fiatCurrencyCode)));             return ticker.getBid();         } catch (CurrencyPairNotValidException e) {             ticker = getTicker(new Currency(coinCode), Currency.BTC);             Ticker ticker2 = getTicker(Currency.BTC, new Currency(fiatCurrencyCode));             return ticker.getBid().multiply(ticker2.getBid());         } catch (IOException e) {             throw new CryptonautException(&quot;Failed to get price for Pair &quot; + coinCode + &quot;\/&quot; + fiatCurrencyCode + &quot;: &quot; + e.getMessage(), e);         }     }     private Ticker getTicker(Currency base, Currency counter) throws CryptonautException {         try {             return marketDataService.getTicker(new CurrencyPair(base, counter));         } catch (CurrencyPairNotValidException | IOException e) {             throw new CryptonautException(&quot;Failed to get price for Pair &quot; + base.getCurrencyCode()                     + &quot;\/&quot; + counter.getCurrencyCode() + &quot;: &quot; + e.getMessage(), e);         }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0441\u043b\u0435\u0433\u043a\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c <a href=\"https:\/\/github.com\/knowm\/XChange\">https:\/\/github.com\/knowm\/XChange<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0432\u0438\u0434\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430 \u043c\u043d\u043e\u0433\u0438\u0445, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043d\u0430 \u0432\u0441\u0435\u0445 \u043a\u0440\u0438\u043f\u0442\u043e\u0431\u0438\u0440\u0436\u0430\u0445 \u0432 \u043e\u0431\u043e\u0440\u043e\u0442\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 (USD, EUR, \u043f\u043e\u0436\u0430\u043b\u0443\u0439 \u0438 \u0432\u0441\u0451..), \u0434\u043b\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u2013 \u043a\u0443\u0440\u0441\u044b \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0435\u0440. \u0422.\u0435. \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u043e\u0438\u0442 \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u0430 WTF \u0432 RUR (\u0446\u0435\u043b\u0435\u0432\u0430\u044f \u0432\u0430\u043b\u044e\u0442\u0430, target currency) \u0441\u0435\u0439\u0447\u0430\u0441, \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u043d\u0430 \u0434\u0432\u0430 \u043f\u043e\u0434\u0432\u043e\u043f\u0440\u043e\u0441\u0430: WTF \/ BaseCurrency (\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0442\u0430\u043a\u043e\u0432\u043e\u0439 USD), BaseCurrency \/ RUR, \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u043d\u043e\u0436\u0438\u0442\u044c \u044d\u0442\u0438 \u0434\u0432\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u0432\u044b\u0434\u0430\u0442\u044c \u043a\u0430\u043a \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. <\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u043f\u043e\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e USD \u0438 RUR.<br \/>  \u0422\u0430\u043a \u0432\u043e\u0442, \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 RUR \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0437\u044f\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438, \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0435 \u0433\u0435\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (\u0431\u0443\u0434\u0435\u043c \u0445\u043e\u0441\u0442\u0438\u0442\u044c \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0443\u0433\u0443\u0431\u043e \u0432 \u0420\u043e\u0441\u0441\u0438\u0438). \u041a\u043e\u0440\u043e\u0447\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u043d\u0430\u0441 \u0443\u0441\u0442\u0440\u043e\u0438\u0442 \u043a\u0443\u0440\u0441 \u0426\u0411. \u041d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0431\u044b\u043b \u043d\u0430\u0439\u0434\u0435\u043d \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0442\u0430\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0442\u044c \u043a\u0430\u043a JSON. \u041f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e. <\/p>\n<p>  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u0442\u0432\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u0443\u0440\u0441\u0430 \u0432\u0430\u043b\u044e\u0442 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442:<\/p>\n<p>  <\/p>\n<pre><code>{     &quot;Date&quot;: &quot;2018-10-16T11:30:00+03:00&quot;,     &quot;PreviousDate&quot;: &quot;2018-10-13T11:30:00+03:00&quot;,     &quot;PreviousURL&quot;: &quot;\\\/\\\/www.cbr-xml-daily.ru\\\/archive\\\/2018\\\/10\\\/13\\\/daily_json.js&quot;,     &quot;Timestamp&quot;: &quot;2018-10-15T23:00:00+03:00&quot;,     &quot;Valute&quot;: {         &quot;AUD&quot;: {             &quot;ID&quot;: &quot;R01010&quot;,             &quot;NumCode&quot;: &quot;036&quot;,             &quot;CharCode&quot;: &quot;AUD&quot;,             &quot;Nominal&quot;: 1,             &quot;Name&quot;: &quot;\u0420\u0452\u0420\u0406\u0421\u0403\u0421\u201a\u0421\u0402\u0420\u00b0\u0420\u00bb\u0420\u0451\u0420\u2116\u0421\u0403\u0420\u0454\u0420\u0451\u0420\u2116 \u0420\u0491\u0420\u0455\u0420\u00bb\u0420\u00bb\u0420\u00b0\u0421\u0402&quot;,             &quot;Value&quot;: 46.8672,             &quot;Previous&quot;: 46.9677         },         &quot;AZN&quot;: {             &quot;ID&quot;: &quot;R01020A&quot;,             &quot;NumCode&quot;: &quot;944&quot;,             &quot;CharCode&quot;: &quot;AZN&quot;,             &quot;Nominal&quot;: 1,             &quot;Name&quot;: &quot;\u0420\u0452\u0420\u00b7\u0420\u00b5\u0421\u0402\u0420\u00b1\u0420\u00b0\u0420\u2116\u0420\u0491\u0420\u00b6\u0420\u00b0\u0420\u0405\u0421\u0403\u0420\u0454\u0420\u0451\u0420\u2116 \u0420\u0458\u0420\u00b0\u0420\u0405\u0420\u00b0\u0421\u201a&quot;,             &quot;Value&quot;: 38.7567,             &quot;Previous&quot;: 38.8889         },         &quot;GBP&quot;: {             &quot;ID&quot;: &quot;R01035&quot;,             &quot;NumCode&quot;: &quot;826&quot;,             &quot;CharCode&quot;: &quot;GBP&quot;,             &quot;Nominal&quot;: 1,             &quot;Name&quot;: &quot;\u0420\u00a4\u0421\u0453\u0420\u0405\u0421\u201a \u0421\u0403\u0421\u201a\u0420\u00b5\u0421\u0402\u0420\u00bb\u0420\u0451\u0420\u0405\u0420\u0456\u0420\u0455\u0420\u0406 \u0420\u040e\u0420\u0455\u0420\u00b5\u0420\u0491\u0420\u0451\u0420\u0405\u0420\u00b5\u0420\u0405\u0420\u0405\u0420\u0455\u0420\u0456\u0420\u0455 \u0420\u0454\u0420\u0455\u0421\u0402\u0420\u0455\u0420\u00bb\u0420\u00b5\u0420\u0406\u0421\u0403\u0421\u201a\u0420\u0406\u0420\u00b0&quot;,             &quot;Value&quot;: 86.2716,             &quot;Previous&quot;: 87.2059         }, ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 <code>CbrExchangeRatesClient<\/code>:<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut.markets.clients; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.room606.cryptonaut.exceptions.CryptonautException; import io.micronaut.http.HttpRequest; import io.micronaut.http.client.Client; import io.micronaut.http.client.RxHttpClient; import javax.inject.Inject; import javax.inject.Singleton; import java.io.IOException; import java.math.BigDecimal; import java.util.*; @Singleton public class CbrExchangeRatesClient {     private static final String CBR_DATA_URI = &quot;https:\/\/www.cbr-xml-daily.ru\/daily_json.js&quot;;     @Client(CBR_DATA_URI) @Inject     private RxHttpClient httpClient;     private final ObjectReader objectReader = new ObjectMapper().reader();     public Map&lt;String, BigDecimal&gt; getRates() {         try {             \/\/return ratesCache.get(&quot;fiatRates&quot;);             HttpRequest&lt;?&gt; req = HttpRequest.GET(&quot;&quot;);             String response = httpClient.retrieve(req, String.class).blockingSingle();             JsonNode json  = objectReader.readTree(response);             String usdPrice = json.get(&quot;Valute&quot;).get(&quot;USD&quot;).get(&quot;Value&quot;).asText();             String eurPrice = json.get(&quot;Valute&quot;).get(&quot;EUR&quot;).get(&quot;Value&quot;).asText();             String gbpPrice = json.get(&quot;Valute&quot;).get(&quot;GBP&quot;).get(&quot;Value&quot;).asText();             Map&lt;String, BigDecimal&gt; prices = new HashMap&lt;&gt;();             prices.put(&quot;USD&quot;, new BigDecimal(usdPrice));             prices.put(&quot;GBP&quot;, new BigDecimal(gbpPrice));             prices.put(&quot;EUR&quot;, new BigDecimal(eurPrice));             return prices;         } catch (IOException e) {             throw new CryptonautException(&quot;Failed to obtain exchange rates: &quot; + e.getMessage(), e);         }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u043c <code>RxHttpClient<\/code>, \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u0442 \u0438\u0437 \u043a\u043e\u043c\u043b\u043f\u0435\u043a\u0442\u0430 <code>Micronaut<\/code>. \u041e\u043d \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u0435\u0442 \u043d\u0430\u043c \u0432\u044b\u0431\u043e\u0440, \u0434\u0435\u043b\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u043b\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0443\u044e. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0443\u044e, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0443\u044e:<\/p>\n<p>  <\/p>\n<pre><code>httpClient.retrieve(req, String.class).blockingSingle();<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"konfiguraciya\">\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0435\u0449\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u043b\u0438 \u043d\u0430 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u043a\u0430\u043a \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0438 \u0431\u0443\u0434\u0435\u043c \u0435\u0433\u043e \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0442\u044c \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434\u044b \u0432\u0430\u043b\u044e\u0442, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u044b \u043d\u0435 \u0432 \u0441\u0438\u043b\u0430\u0445 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f:<\/p>\n<p>  <\/p>\n<pre><code>public BigDecimal getFiatPrice(String baseCurrency, String counterCurrency) throws NotSupportedFiatException {     if (!supportedCounterCurrencies.contains(counterCurrency)) {         throw new NotSupportedFiatException(&quot;Counter currency not supported: &quot; + counterCurrency);     }     Map&lt;String, BigDecimal&gt; rates = cbrExchangeRatesClient.getRates();     return rates.get(baseCurrency); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0435 \u2013 \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 <code>application.yml<\/code> \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>supportedCounterCurrencies<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u044b\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434, \u043d\u0438\u0436\u0435 \u043f\u043e\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 FiatExchangeRatesService.java:<\/p>\n<p>  <\/p>\n<pre><code>@Value(&quot;${cryptonaut.currencies:RUR}&quot;) private String supportedCurrencies; private final List&lt;String&gt; supportedCounterCurrencies = Arrays.asList(supportedCurrencies.split(&quot;[,]&quot;, -1));<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c <code>placeholder<\/code> c\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 <code>application.yml<\/code> \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code>micronaut:     application:         name: cryptonaut  #Uncomment to set server port     server:         port: 8080 postgres:     reactive:         client:             port: 5432             host: localhost             database: cryptonaut             user: crypto             password: r1ch13r1ch             maxSize: 5 # app \/ business logic specific properties cryptonaut:     currencies: &quot;RUR&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0431\u044b\u0441\u0442\u0440\u044b\u0439 smoke-\u0442\u0435\u0441\u0442\u2026 \u041e\u0448\u0438\u0431\u043a\u0430!<\/p>\n<p>  <\/p>\n<pre><code>Caused by: io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [com.room606.cryptonaut.markets.CryptoMarketDataService]  Path Taken: new MarketDataController([CryptoMarketDataService cryptoMarketDataService],FiatExchangeRatesService fiatExchangeRatesService) --&gt; new CryptoMarketDataService([FiatExchangeRatesService fiatExchangeRatesService],MarketDataServiceFactory marketDataServiceFactory)     at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1266)     at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:1677)     at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1447)     at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1427)     at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:852)     at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:943)     ... 36 common frames omitted Caused by: java.lang.NullPointerException: null     at com.room606.cryptonaut.markets.FiatExchangeRatesService.&lt;init&gt;(FiatExchangeRatesService.java:20)     at com.room606.cryptonaut.markets.$FiatExchangeRatesServiceDefinition.build(Unknown Source)     at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1252)     ... 41 common frames omitted<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <code>Micronaut<\/code> \u0442\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 <code>Spring<\/code> \u0437\u0434\u0435\u0441\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0441\u0451 \u0442\u0430\u043a\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f <code>compile time<\/code>. \u0414\u043e\u0441\u0430\u0434\u043d\u043e \u043f\u043e\u043a\u043e\u0440\u0438\u0432 \u0441\u0435\u0431\u044f \u0437\u0430 \u0442\u0430\u043a\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443 \u043d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u0434 \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<p>  <\/p>\n<pre><code>@Value(&quot;${cryptonaut.currencies:RUR}&quot;) private String supportedCurrencies; private List&lt;String&gt; supportedCounterCurrencies;  @PostConstruct void init() {     supportedCounterCurrencies = Arrays.asList(supportedCurrencies.split(&quot;[,]&quot;, -1)); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430, \u0441\u0442\u0430\u0440\u044b\u0439 \u0434\u043e\u0431\u0440\u044b\u0439 \u0434\u0440\u0443\u0433 \u2013 <code>javax.annotation.PostConstruct<\/code>, \u043d\u0430\u0441 \u0437\u0434\u0435\u0441\u044c \u0432\u044b\u0440\u0443\u0447\u0438\u043b \u0438 \u043f\u0440\u043e\u0438\u043d\u0436\u0435\u043a\u0442\u0438\u043b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u0431\u0438\u043d \u0443\u0436\u0435 \u0440\u043e\u0434\u0438\u043b\u0441\u044f, \u0436\u0438\u0432 \u0438 \u0433\u043e\u0442\u043e\u0432 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u043d\u043e \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0435\u0449\u0435 \u043d\u0435 \u043e\u0431\u044a\u044f\u0432\u0438\u043b\u043e \u043e \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438. \u0421\u0430\u043c\u044b\u0439 \u043d\u0443\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u043d\u0430\u0441.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c, \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441, \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0430\u043a\u0438\u0435 \u0436\u0435 \u043a\u0430\u043a \u0438 \u0432 Spring. \u041d\u0430\u0440\u044f\u0434\u0443 \u0441 \u044d\u0442\u0438\u043c micronaut \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@Property<\/code> \u0434\u043b\u044f \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0447\u043a\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <code>Map&lt;String, String&gt;<\/code>, \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>@Configuration<\/code> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439, <code>Random Properties<\/code> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0442\u044c \u043f\u0441\u0435\u0432\u0434\u043e\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u0430\u043a <code>ID<\/code> \u043d\u0435\u043a\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0443\u0434\u043e\u0431\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0445-\u043d\u0438\u0431\u0443\u0434\u044c \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439 \u043f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435) \u0438 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044e <code>PropertySourceLoader<\/code>, \u0442.\u0435. \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439. \u0411\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u0430\u043d\u0430\u043b\u043e\u0433 \u0432 <code>Spring<\/code> \u2013 \u044d\u0442\u043e \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 <code>ApplicationContext<\/code> (<code>xml<\/code>, <code>web<\/code>, <code>groovy<\/code>, <code>ClassPath<\/code> etc.) \u0412\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0438 \u044d\u0442\u043e\u0442 \u0430\u0441\u043f\u0435\u043a\u0442 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043d \u0438 \u0437\u0430\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u043e \u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e.<\/p>\n<p>  <\/p>\n<h3 id=\"testy\">\u0422\u0435\u0441\u0442\u044b<\/h3>\n<p>  <\/p>\n<p>\u041f\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u044f \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0432\u043f\u0435\u0447\u0430\u0442\u043b\u0438\u043b\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 micronaut. \u041d\u0430\u043c \u0440\u0435\u043a\u043b\u0430\u043c\u0438\u0440\u0443\u044e\u0442 Embedded Server feature, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 <code>Groovy<\/code> \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 <code>Spock<\/code>. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0442\u043e\u043f\u0438\u043c \u0437\u0430 <code>Java<\/code>, \u0442\u043e groovy-\u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u043c\u0438\u043c\u043e. \u0412\u043e\u043e\u0431\u0449\u0435\u043c, \u044f \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0442\u043e\u043b\u044c\u043a\u043e <code>EmbeddedServer<\/code> + <code>HttpClient<\/code> \u0438\u0437 \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0438 <code>Micronaut<\/code> \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u043e\u0434\u043d\u0443 \u0438\u0437 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 API \u2014 <\/p>\n<p>  <\/p>\n<pre><code>GET \/cryptonaut\/restapi\/portfolio\/total.json?fiatCurrency={x}<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 API, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u0443\u044e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0430\u043b\u044e\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0444\u0435\u043b\u044f \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432 \u043d\u0435\u043a\u043e\u0439 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0444\u0438\u0430\u0442\u043d\u043e\u0439 \u0432\u0430\u043b\u044e\u0442\u0435.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u0430 \u043d\u0438\u0436\u0435:<\/p>\n<p>  <\/p>\n<pre><code>public class PortfolioReportsControllerTest {     private static EmbeddedServer server;     private static HttpClient client;     @Inject     private PortfolioService portfolioService;     @BeforeClass     public static void setupServer() {         server = ApplicationContext.run(EmbeddedServer.class);         client = server                 .getApplicationContext()                 .createBean(HttpClient.class, server.getURL());     }     @AfterClass     public static void stopServer() {         if(server != null) {             server.stop();         }         if(client != null) {             client.stop();         }     }     @Test     public void total() {         \/\/TODO: Seems like code smell. I don't like it..         portfolioService = server.getApplicationContext().getBean(PortfolioService.class);         Portfolio portfolio = new Portfolio();         Map&lt;String, BigDecimal&gt; coins = new HashMap&lt;&gt;();         BigDecimal amt1 = new BigDecimal(&quot;570.05&quot;);         BigDecimal amt2 = new BigDecimal(&quot;2.5&quot;);         coins.put(&quot;XRP&quot;, amt1);         coins.put(&quot;QTUM&quot;, amt2);         portfolio.setCoins(coins);         portfolioService.savePortfolio(portfolio);         HttpRequest request = HttpRequest.GET(&quot;\/cryptonaut\/restapi\/portfolio\/total.json?fiatCurrency=USD&quot;);         HttpResponse&lt;Total&gt; rsp = client.toBlocking().exchange(request, Total.class);         assertEquals(200, rsp.status().getCode());         assertEquals(MediaType.APPLICATION_JSON_TYPE, rsp.getContentType().get());         Total val = rsp.body();         assertEquals(&quot;USD&quot;, val.getFiatCurrency());         assertEquals(TEST_VALUE.toString(), val.getValue().toString());         assertEquals(amt1.toString(), val.getPortfolio().getCoins().get(&quot;XRP&quot;).toString());         assertEquals(amt2.toString(), val.getPortfolio().getCoins().get(&quot;QTUM&quot;).toString());     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0437 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0442\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u0446\u0435\u043b\u0435\u0439 \u0442\u0435\u0441\u0442\u0430 \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 mock \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <code>PortfolioService.java<\/code>:<\/p>\n<p>  <\/p>\n<pre><code>package com.room606.cryptonaut;  import com.room606.cryptonaut.domain.Portfolio; import io.micronaut.context.annotation.Requires; import javax.inject.Singleton; import java.math.BigDecimal; import java.util.Optional;  @Singleton @Requires(env=&quot;test&quot;) public class MockPortfolioService implements PortfolioService {     private Portfolio portfolio;     public static final BigDecimal TEST_VALUE = new BigDecimal(&quot;56.65&quot;);     @Override     public Portfolio savePortfolio(Portfolio portfolio) {         this.portfolio = portfolio;         return portfolio;     }     @Override     public Portfolio loadPortfolio() {         return portfolio;     }     @Override     public Optional&lt;BigDecimal&gt; calculateTotalValue(Portfolio portfolio, String fiatCurrency) {         return Optional.of(TEST_VALUE);     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>@Requires(env=&quot;test&quot;)<\/code>, \u044d\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0438\u043d\u043e\u0432 \u0432 <code>Application Context<\/code> \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 micronaut \u043f\u043e\u0434\u044b\u043c\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438 test, \u0438 \u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u0435\u0441\u0442\u0430\u0445. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442 \u0430\u0432\u0442\u043e\u0432\u0430\u0439\u0440\u0438\u043d\u0433\u0430 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0438 \u043d\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0438\u0441\u0442\u0438\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>PortfolioServiceImpl<\/code> \u0431\u044b\u043b\u0430 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0438\u0441\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0435\u0439 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@Requires(notEnv=&quot;test&quot;)<\/code>. \u0412\u043e\u0442 \u0442\u0430\u043a\u0438\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0435\u043b\u043e\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0433\u0438\u0431\u043a\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430\u0445 \u2013 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u043d\u0430 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0435. \u0417\u0434\u0435\u0441\u044c <code>Micronaut<\/code> \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u0435\u0431\u044f \u043f\u0440\u043e\u044f\u0432\u0438\u043b \u0438 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0435\u043d\u0438\u0439 \u0432 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435 \u0432\u044b\u0437\u0432\u0430\u043b.<\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430, \u043a\u0430\u043a \u0442\u043e \u2013 \u0440\u0430\u0441\u0447\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438, \u0440\u0430\u0441\u0447\u0435\u0442 \u0446\u0435\u043d\u044b \u0432 \u0444\u0438\u0430\u0442\u043d\u043e\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0438, \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u2013 \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u044b \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c <code>mockito<\/code>. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043e\u0434\u0438\u043d \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432 \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430:<\/p>\n<p>  <\/p>\n<pre><code>@Test public void priceForUsdDirectRate() throws IOException {     when(marketDataServiceFactory.getMarketDataService()).thenReturn(marketDataService);     String coinCode = &quot;ETH&quot;;     String fiatCurrencyCode = &quot;USD&quot;;     BigDecimal priceA = new BigDecimal(&quot;218.58&quot;);     Ticker targetTicker = new Ticker.Builder().bid(priceA).build();     when(marketDataService.getTicker(new CurrencyPair(new Currency(coinCode), new Currency(fiatCurrencyCode)))).thenReturn(targetTicker);     CryptoMarketDataService cryptoMarketDataService = new CryptoMarketDataService(fiatExchangeRatesService, marketDataServiceFactory);     assertEquals(priceA, cryptoMarketDataService.getPrice(coinCode, fiatCurrencyCode)); }<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"keshirovanie\">\u041a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043e\u0434\u043d\u0430 \u0432\u0435\u0449\u044c \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e. \u041a\u0443\u0440\u0441 \u0444\u0438\u0430\u0442\u043d\u044b\u0445 \u0432\u0430\u043b\u044e\u0442 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0430\u043a \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0426\u0411. \u0418 \u043a\u0430\u043a \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u043e\u043d \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437 \u0432 \u0441\u0443\u0442\u043a\u0438 \u0438 \u043a\u0443\u0440\u0441 \u0430\u043a\u0442\u0443\u0430\u043b\u0435\u043d \u0440\u043e\u0432\u043d\u043e \u0441\u0443\u0442\u043a\u0438. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0441\u043c\u044b\u0441\u043b\u0430 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0440\u0430\u0437 \u0437\u0430 \u0440\u0430\u0437\u043e\u043c, \u0440\u0438\u0441\u043a\u0443\u044f \u043d\u0430\u0440\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0442\u0440\u043e\u0442\u0442\u043b\u0438\u043d\u0433 \u0438\u043b\u0438 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0431\u0430\u043d \u043f\u043e IP. \u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0440\u043e\u043f\u0435\u0440\u0442\u0435\u0439 \u0438 \u043d\u0430\u0432\u0435\u0448\u0438\u0432\u0430\u043d\u0438\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@Cacheable<\/code> \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u0438\u043c\u0435\u043d\u0438 \u043a\u0435\u0448\u0430.  <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yz\/xn\/mc\/yzxnmcojgibaurai_jflh202xic.jpeg\" alt=\"\u041a\u0435\u0448\"\/><\/p>\n<p>  \u041e\u0434\u043d\u0430\u043a\u043e, \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435 \u0437\u0430\u0434\u0430\u043b\u043e\u0441\u044c. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0432 \u044d\u0442\u043e\u043c \u0430\u0441\u043f\u0435\u043a\u0442\u0435 \u0441\u0431\u0438\u0432\u0430\u0435\u0442 \u0441 \u0442\u043e\u043b\u043a\u0443, \u0433\u0434\u0435 \u043f\u0440\u043e\u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0432 \u043f\u0430\u0440\u0443 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0435\u0448\u044c \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0430\u0449\u0438\u0435 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0443 \u043a\u0443\u0441\u043a\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 (<code>appliction.yml<\/code>). \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u0435\u0448\u0430 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d redis, \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0439 \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0440\u044f\u0434\u044b\u0448\u043a\u043e\u043c. \u0412\u043e\u0442 \u0435\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f:  <\/p>\n<pre><code>redis:   image: 'bitnami\/redis:latest'   environment:     - ALLOW_EMPTY_PASSWORD=yes   ports:     - '6379:6379'<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0432\u043e\u0442 \u043a\u0443\u0441\u043e\u043a \u043a\u043e\u0434\u0430 \u043f\u0440\u043e\u0430\u043d\u043d\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 @Cacheable:<\/p>\n<p>  <\/p>\n<pre><code>@Cacheable(&quot;fiatRates&quot;) public Map&lt;String, BigDecimal&gt; getRates() {     HttpRequest&lt;?&gt; req = HttpRequest.GET(&quot;&quot;);     String response = httpClient.retrieve(req, String.class).blockingSingle();     try {         JsonNode json  = objectReader.readTree(response);         String usdPrice = json.get(&quot;Valute&quot;).get(&quot;USD&quot;).get(&quot;Value&quot;).asText();         String eurPrice = json.get(&quot;Valute&quot;).get(&quot;EUR&quot;).get(&quot;Value&quot;).asText();         String gbpPrice = json.get(&quot;Valute&quot;).get(&quot;GBP&quot;).get(&quot;Value&quot;).asText();         Map&lt;String, BigDecimal&gt; prices = new HashMap&lt;&gt;();         prices.put(&quot;USD&quot;, new BigDecimal(usdPrice));         prices.put(&quot;GBP&quot;, new BigDecimal(gbpPrice));         prices.put(&quot;EUR&quot;, new BigDecimal(eurPrice));         return prices;     } catch (IOException e) {         throw new RuntimeException(e);     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0432\u043e\u0442 \u0441 <code>application.yml<\/code> \u0431\u044b\u043b\u0430 \u0441\u0430\u043c\u0430\u044f \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u0437\u0430\u0433\u0430\u0434\u043a\u0430. \u042f \u043f\u0435\u0440\u0435\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0432\u0441\u044f\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0412\u043e\u0442 \u0442\u0430\u043a\u0443\u044e:<\/p>\n<p>  <\/p>\n<pre><code>caches:     fiatrates:         expireAfterWrite: &quot;1h&quot; redis:     caches:         fiatRates:             expireAfterWrite: &quot;1h&quot;         port: 6381         server: localhost<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a\u0443\u044e:<\/p>\n<p>  <\/p>\n<pre><code>#cache     redis:         uri: localhost:6379         caches:             fiatRates:                 expireAfterWrite: &quot;1h&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0434\u0430\u0436\u0435 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u0443\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0435\u0440\u0445\u043d\u0438\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u0431\u0443\u043a\u0432 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u043a\u0435\u0448\u0430. \u041d\u043e \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u043b \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u201cUnexpected error occurred: No cache configured for name: fiatRates\u201d:<\/p>\n<p>  <\/p>\n<pre><code>ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: No cache configured for name: fiatRates io.micronaut.context.exceptions.ConfigurationException: No cache configured for name: fiatRates     at io.micronaut.cache.DefaultCacheManager.getCache(DefaultCacheManager.java:67)     at io.micronaut.cache.interceptor.CacheInterceptor.interceptSync(CacheInterceptor.java:176)     at io.micronaut.cache.interceptor.CacheInterceptor.intercept(CacheInterceptor.java:128)     at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)     at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:147)     at com.room606.cryptonaut.markets.clients.$CbrExchangeRatesClientDefinition$Intercepted.getRates(Unknown Source)     at com.room606.cryptonaut.markets.FiatExchangeRatesService.getFiatPrice(FiatExchangeRatesService.java:30)     at com.room606.cryptonaut.rest.MarketDataController.index(MarketDataController.java:34)     at com.room606.cryptonaut.rest.$MarketDataControllerDefinition$$exec2.invokeInternal(Unknown  ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0438\u0441\u043a \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043d\u0430 <code>GitHub<\/code>-\u0435 \u0438\u043b\u0438 \u043f\u043e <code>SO<\/code> \u043d\u0435 \u043f\u043e\u043c\u043e\u0433 \u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443. \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043a\u043e\u043f\u0430\u0432\u0448\u0438\u0441\u044c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u0445 \u0442\u0430\u043a\u0436\u0435 \u0431\u044b\u043b \u0440\u0430\u0441\u0442\u0435\u0440\u044f\u043d \u0438 \u043f\u0430\u043b \u0434\u0443\u0445\u043e\u043c. \u0417\u0430\u0442\u0435\u044f \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u043b\u0430\u0441\u044c, \u0436\u0430\u043b\u044c. \u0410 \u0432\u0435\u0434\u044c \u0432 \u043f\u043b\u0430\u043d\u0430\u0445 \u0435\u0449\u0451 \u0431\u044b\u043b\u0430 \u0437\u0430\u0434\u0443\u043c\u043a\u0430 \u0434\u0430\u043b\u0435\u0435 \u043d\u0430\u0432\u0435\u0441\u0438\u0442\u044c \u043a\u043e\u0434, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0439\u0441\u044f \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0438 \u0438\u043d\u0432\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u043e\u0442 \u043a\u0435\u0448. \u041f\u0438\u0441\u0430\u0442\u044c \u043a\u0435\u0448\u0438\u0440\u0443\u044e\u0449\u0438\u0439 boilerplate-\u043a\u043e\u0434, \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043a\u0430\u0436\u0435\u043c <code>Redis<\/code>-\u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u044f \u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b, \u043c\u044b\u0441\u043b\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0432, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c Spring Boot \u043e\u0442\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u043e\u0431\u0435\u0434\u0443, \u0438\u043c\u0435\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u043d\u0443\u044e \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438 \u043f\u043e\u043c\u043e\u0449\u044c \u043a\u043e\u043c\u044c\u044e\u043d\u0438\u0442\u0438.<\/p>\n<p>  <\/p>\n<h3 id=\"sidim-v-kustah-s-sekundomerom\">\u0421\u0438\u0434\u0438\u043c \u0432 \u043a\u0443\u0441\u0442\u0430\u0445 \u0441 \u0441\u0435\u043a\u0443\u043d\u0434\u043e\u043c\u0435\u0440\u043e\u043c<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0443\u0442\u043e\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u0441\u0442\u0432\u0430 \u0438 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0438\u043b\u0438 \u043e\u043f\u0440\u043e\u0432\u0435\u0440\u0433\u043d\u0443\u0442\u044c \u0442\u043e, \u0447\u0442\u043e \u043f\u0440\u0435\u043f\u043e\u0434\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u0432\u0435\u0441\u043e\u043c\u043e\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e <code>Micronaut<\/code> \u2013 \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u0440\u0442\u0430, \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043c\u0435\u0440\u043e\u0432 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441\u0440\u0435\u0434\u043d\u0438\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438 \u0441\u043e Spring-\u043e\u043c.  <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6z\/nu\/h5\/6znuh5vgxk7g0vueo5vs1ktkznc.jpeg\" alt=\"Benchmarking\"\/><\/p>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0441 \u0434\u044e\u0436\u0438\u043d\u0443 Disclaimer-\u043e\u0432: \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u044f \u043d\u0435 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a-\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442, \u043e \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0437\u0430\u043c\u0435\u0440\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0442\u0430\u0440\u0442\u0430, \u043e\u0431 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430 (\u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043c\u0430\u0448\u0438\u043d\u044b, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0436\u0435\u043b\u0435\u0437\u0430, \u041e\u0421, \u043f\u0440\u043e\u0447\u0435\u0435).   <\/p>\n<p>\u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0443\u043a\u0430\u0436\u0443:<\/p>\n<p>  <\/p>\n<p><strong>OS:<\/strong> 16.04.1-Ubuntu x86_64 x86_64 x86_64 GNU\/Linux<br \/>  <strong>CPU:<\/strong> Intel&reg; Core(TM) i7-7700HQ CPU @ 2.80GHz<br \/>  <strong>Mem:<\/strong> 2 \u043f\u043b\u0430\u0448\u043a\u0438 \u043f\u043e 8 Gb DDR4, Speed: 2400 MHz<br \/>  <strong>SSD Disk:<\/strong> \u0422\u0432\u0435\u0440\u0434\u043e\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u043a\u043e\u043f\u0438\u0442\u0435\u043b\u044c PCIe NVMe M.2, 256 \u0413\u0431\u0430\u0439\u0442<\/p>\n<p>  <\/p>\n<p>\u041c\u043e\u044f <del>\u043e\u0431\u043e\u0440\u043e\u043d\u0430<\/del> \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0430:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u041f\u043e\u0433\u0430\u0441\u0438\u0442\u044c \u0442\u0430\u0447\u043a\u0443<\/li>\n<li>\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u0430\u0447\u043a\u0443<\/li>\n<li>\u0421\u0442\u0430\u0440\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/li>\n<li>\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u0434 \u0432 \u0446\u0438\u043a\u043b\u0435 \u043e\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 API, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0434\u0430\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435<\/li>\n<li>\u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 API \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u2013 \u201c\u0442\u0430\u0439\u043c\u0435\u0440\u201d \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/li>\n<li>\u0412 \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0443 \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u0418 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0441 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u043d\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u043c\u0438 \u043d\u0430\u0431\u043e\u0440\u0430\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u2013 \u043e\u0434\u0438\u043d <code>Rest Controller<\/code> \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a\u043b\u0430\u0441\u0441 \u2013 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0439 IoC-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0432\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0441\u0440\u0435\u0434\u043d\u0438\u0445 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u201c\u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0442\u0430\u0440\u0442\u0430\u201d \u0437\u0430\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043d\u0438\u0436\u0435:<\/p>\n<p>  <\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Micronaut<\/th>\n<th>Spring Boot<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Avg.(ms)<\/td>\n<td>2708.4<\/td>\n<td>2735.2<\/td>\n<\/tr>\n<tr>\n<td>\u0421\u0442\u0430\u0440\u0442\u0430\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f cryptonaut \u043f\u043e \u0432\u0435\u0440\u0441\u0438\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 (ms)<\/td>\n<td>1082<\/td>\n<td>&#8212;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u043d\u0430 \u0442\u0430\u043a\u0438\u0445 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0430 \u2013 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 <strong>27<\/strong> \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 <code>Micronaut<\/code>. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0449\u0443\u0442\u0438\u043c\u0435\u0435 \u0441 \u0440\u043e\u0441\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0441\u0432\u044f\u0437\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438.<\/p>\n<p>  <\/p>\n<h3 id=\"chto-po-itogu\">\u0427\u0442\u043e \u043f\u043e \u0438\u0442\u043e\u0433\u0443?<\/h3>\n<p>  <\/p>\n<p>\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0442\u043e\u0433\u0438. \u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0446\u0435\u043b\u044c, \u0430 \u043e\u043d\u0430 \u0431\u044b\u043b\u0430, \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e, \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043d\u043e\u0432\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u2013 \u0431\u044b\u043b\u0430 \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430. \u041d\u0430 \u044d\u0442\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0441\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u0434\u0430\u0436\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u043d\u0430\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0442\u043e\u0447\u0435\u043d\u0430 \u043f\u043e\u0434 Groovy-\u0430\u0434\u0435\u043f\u0442\u043e\u0432, \u0438 \u044d\u0442\u043e \u043d\u0435 \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0435\u0441\u043b\u0438 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043a\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041d\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0442\u0443\u0441\u043e\u0432\u043a\u0438 \u043d\u0430 <a href=\"https:\/\/stackoverflow.com\/\"><code>SO<\/code><\/a> \u043a\u0430\u043a \u0443 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 Spring. \u041d\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u0440\u0443\u0436\u0435\u043b\u044e\u0431\u0435\u043d \u0434\u043b\u044f \u043d\u043e\u0432\u0447\u0438\u043a\u0430 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441. \u041d\u043e \u0434\u0430\u0431\u044b \u043d\u0435 \u043b\u0443\u043a\u0430\u0432\u0438\u0442\u044c \u0441\u043a\u0430\u0436\u0443 \u0441\u0430\u043c \u0437\u0430 \u0441\u0435\u0431\u044f \u2014 \u044f \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043e\u0441\u0442\u0430\u043d\u0443\u0441\u044c \u0432 \u043b\u0430\u0433\u0435\u0440\u0435 \u0412\u0435\u0441\u043d\u0443\u0448\u0435\u0447\u043d\u0438\u043a\u043e\u0432. \u0423\u0436 \u0431\u043e\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043d\u0430\u0431\u0438\u0442\u0430 \u0440\u0443\u043a\u0430 \u0438 \u0437\u0430\u0442\u043e\u0447\u0435\u043d\u043e \u043c\u044b\u0448\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0434 \u0438\u0434\u0435\u043e\u043b\u043e\u0433\u0438\u044e Spring.<\/p>\n<p>  <\/p>\n<p><strong>\u0427\u0442\u043e \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043d\u043e:<\/strong><\/p>\n<p>  <\/p>\n<ul>\n<li>\u043c\u043d\u043e\u0433\u0438\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0444\u0438\u0448\u043a\u0438 Micronaut \u2013 \u0432\u0441\u044f\u0447\u0435\u0441\u043a\u0438\u0435 service-discovery, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043b\u044f\u043c\u0431\u0434 \u0432 AWS<\/li>\n<li>\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/li>\n<li>\u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u043d\u0430 Java. \u0422\u043e \u0435\u0441\u0442\u044c \u043d\u0430 Kotlin \u043b\u0438\u0431\u043e \u043d\u0430 Groovy.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c <a href=\"https:\/\/marazmatIK@bitbucket.org\/marazmatIK\/cryptonaut.git\">\u0442\u0443\u0442<\/a>.<\/p>\n<\/div>\n<p>        <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d()}}}t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>     <br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/post\/427595\/\"> https:\/\/habr.com\/post\/427595\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<h2 id=\"probuem-micronaut-ili-dorogaya-ya-umenshil-freymvork\">\u041f\u0440\u043e\u0431\u0443\u0435\u043c Micronaut \u0438\u043b\u0438 \u0414\u043e\u0440\u043e\u0433\u0430\u044f, \u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a<\/h2>\n<p>  <\/p>\n<p>\u041f\u0440\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a micronaut \u044f \u043c\u0435\u043b\u044c\u043a\u043e\u043c \u0432\u044b\u0447\u0438\u0442\u0430\u043b \u0438\u0437 \u0434\u0430\u0439\u0434\u0436\u0435\u0441\u0442 \u0440\u0430\u0441\u0441\u044b\u043b\u043e\u043a. \u0417\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0441\u044f, \u0447\u0442\u043e \u0437\u0430 \u0437\u0432\u0435\u0440\u044c \u0442\u0430\u043a\u043e\u0439. \u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0432\u0435\u0437 \u043d\u0430\u043f\u0438\u0447\u043a\u0430\u043d\u043d\u043e\u043c\u0443 \u0432\u0441\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c Spring. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/eu\/iq\/eq\/euiqeqqehjcvuto1psel_ajypw4.jpeg\" alt=\"Micronaut\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u0432\u043e\u0441\u0445\u0438\u0449\u0430\u044f \u0433\u0440\u044f\u0434\u0443\u0449\u0443\u044e \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0433\u0434\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c micronaut \u0432 \u0432\u0430\u0448\u0438\u0445 \u044d\u0442\u0438\u0445 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u044f \u0440\u0435\u0448\u0438\u043b \u0445\u043e\u0442\u044c \u0440\u0430\u0437 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u0440\u0438\u0439\u0442\u0438 \u0445\u043e\u0442\u044c \u0441 \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0432 \u0433\u043e\u043b\u043e\u0432\u0435, \u0441 \u043d\u0435\u043a\u0438\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432. \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435. \u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043b\u0430\u0431\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 pet-project \u0437\u0430 \u043f\u0430\u0440\u0443-\u0442\u0440\u043e\u0439\u043a\u0443 \u0432\u0435\u0447\u0435\u0440\u043e\u0432 (\u043a\u0430\u043a \u043f\u043e\u0439\u0434\u0451\u0442). \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432\u0441\u0435\u0445 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-291305","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/291305","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=291305"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/291305\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=291305"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=291305"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=291305"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}