{"id":459985,"date":"2025-05-16T15:02:23","date_gmt":"2025-05-16T15:02:23","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=459985"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=459985","title":{"rendered":"<span>gRPC \u2014 \u043d\u043e\u0432\u044b\u0439 Rest. \u0421\u0435\u043a\u0440\u0435\u0442\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0432 Spring Boot<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043c\u0438\u0440\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u0434\u0430 \u0432 \u0431\u044b\u0441\u0442\u0440\u043e\u043c \u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u043a\u0430\u043a \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 Rest API \u043a \u043d\u0430\u043c \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 gRPC. \u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 gRPC \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Boot \u0438 Java 17, \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0441\u0432\u043e\u0451 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 gRPC.<\/p>\n<h3>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0442\u0435\u043e\u0440\u0438\u0438<\/h3>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/uh\/e0\/-c\/uhe0-cvzzo0yjfwnd_ci0xbquxs.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/uh\/e0\/-c\/uhe0-cvzzo0yjfwnd_ci0xbquxs.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/uh\/e0\/-c\/uhe0-cvzzo0yjfwnd_ci0xbquxs.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432<\/figcaption><\/div>\n<\/figure>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 gRPC?<\/h4>\n<p>gRPC (Google Remote Procedure Calls) &#8212; \u044d\u0442\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b (RPC) \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f IT-\u0433\u0438\u0433\u0430\u043d\u0442\u043e\u043c Google. \u0414\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b HTTP\/2, \u0430 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Protocol Buffers. \u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u0438\u043c\u0438 \u044f\u0437\u044b\u043a\u0430\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a: Java, C++, Python \u0438 \u0434\u0440\u0443\u0433\u0438\u0435. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u0432 <a href=\"https:\/\/grpc.io\/docs\/\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 gRPC<\/a>.<\/p>\n<h3>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430<\/h3>\n<ol>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u2013 \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e HTTP\/2 \u0438 protobuf, gRPC \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043d\u0443\u044e \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u2013 \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 protobuf \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u2013 \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u0445, \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0443\u043f\u0440\u043e\u0449\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u2013 gRPC \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442, \u043d\u043e \u0438 \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043b\u043d\u044b\u0439 \u0434\u0443\u043f\u043b\u0435\u043a\u0441, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0433\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0447\u0430\u0442\u0430\u0445 \u0438\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043e\u0434\u0430 \u2013 gRPC \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 (stubs), \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0441\u043d\u0438\u0436\u0430\u044f \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a. \u042d\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/li>\n<\/ol>\n<h3>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/h3>\n<ol>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430 \u2013 \u0414\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 gRPC \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f protobuf \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP\/2. \u041e\u0434\u043d\u0430\u043a\u043e \u0441 \u043e\u043f\u044b\u0442\u043e\u043c \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 \u2013 \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 gRPC \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a gRPC-Web \u0438\u043b\u0438 \u043f\u0440\u043e\u043a\u0441\u0438-\u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u0447\u0442\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 Protocol Buffers \u2013 \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 protobuf \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043f\u0440\u0438\u0432\u044b\u043a \u043a JSON \u0438\u043b\u0438 XML. \u0425\u043e\u0442\u044f protobuf \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u0435\u043d, \u043e\u043d \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u2013 \u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 gRPC \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 HTTP\/2 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0435\u0441\u043b\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u043e\u0434 HTTP\/2.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 Protocol Buffers<\/h3>\n<p>ProtoBuf \u2014 \u044d\u0442\u043e \u044f\u0437\u044b\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 Google. \u041e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 ProtoBuf \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .proto. \u042d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0432 \u041e\u041e\u041f) \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e). \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/protobuf.dev\/overview\/\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0412\u043e\u0442, \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>message Area {     string id = 1;     string title = 2;     string description = 3;     string address = 4;     google.protobuf.Timestamp creationDateTime = 5;     google.protobuf.Timestamp updateDateTime = 6;     Coordinate Coordinate = 7; } <\/code><\/pre>\n<p>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code>service AreaService {     rpc GetAreas (google.protobuf.Empty) returns (AreaList) {};     rpc GetAreaById (AreaId) returns (Area) {};     rpc CreateArea (AreaToCreate) returns (AreaId) {};     rpc SaveFile (File) returns (google.protobuf.Empty) {};     rpc StreamingFile (stream File) returns (google.protobuf.Empty) {}; } <\/code><\/pre>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 ProtoBuf<\/h4>\n<p>int32 (\u0434\u043b\u044f int) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>int64 (\u0434\u043b\u044f long) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>float \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>double \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>bool \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: false<\/p>\n<p>string \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430<\/p>\n<p>byte (\u0434\u043b\u044f byte[])<\/p>\n<p>repeated (\u0434\u043b\u044f List\/Collection)<\/p>\n<p>map (\u0434\u043b\u044f Map) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: empty map<\/p>\n<p>enum \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: \u043f\u0435\u0440\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u043e\u0431\u0451\u0440\u0442\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a &#171;google\/protobuf\/timestamp.proto&#187; \u0434\u043b\u044f \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<h3>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043e\u0434\u0438\u043d \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u0434\u0432\u0430 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0441 gRPC \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438:<\/p>\n<ol>\n<li>\n<p>gRPC-interface: \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 .proto \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 Java \u043a\u043b\u0430\u0441\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>gRPC-server: \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e gRPC &#171;\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432&#187; \u0438 gRPC-interface \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 Maven \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>gRPC-client: \u041b\u044e\u0431\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Java, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u043d\u0430\u0448\u0438\u043c gRPC &#171;\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c&#187;.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441 gRPC \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u043c, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<h4>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0443\u0434\u0443\u0442:<\/h4>\n<ol>\n<li>\n<p>Spring Boot<\/p>\n<\/li>\n<li>\n<p>Spring Cloud<\/p>\n<\/li>\n<li>\n<p>gRPC<\/p>\n<\/li>\n<li>\n<p>Rest API<\/p>\n<\/li>\n<li>\n<p>Swagger<\/p>\n<\/li>\n<li>\n<p>OAuth 2.0<\/p>\n<\/li>\n<li>\n<p>MapStruct<\/p>\n<\/li>\n<li>\n<p>Spring Data Jpa\/Hibernate<\/p>\n<\/li>\n<li>\n<p>PostgreSQL<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443.<\/p>\n<ol>\n<li>\n<p>Eureka Server<\/p>\n<\/li>\n<li>\n<p>API Gateway<\/p>\n<\/li>\n<li>\n<p>grpc-interface<\/p>\n<\/li>\n<li>\n<p>area-client<\/p>\n<\/li>\n<li>\n<p>area-server<\/p>\n<\/li>\n<\/ol>\n<blockquote>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c\u0441\u044f grpc-interface, area-client, area-server.<\/p>\n<\/blockquote>\n<h4>grpc-interface<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0438\u043c area.proto \u0444\u0430\u0439\u043b \u0438 \u043e\u043f\u0438\u0448\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b.<\/p>\n<pre><code>syntax = \"proto3\";  import \"google\/protobuf\/timestamp.proto\"; import \"google\/protobuf\/empty.proto\";  package ru.acgnn.grpc.area;  option java_multiple_files = true; option java_package = \"ru.acgnn.grpc\"; option java_outer_classname = \"AreaServerGrpcProto\";  service AreaService {     rpc GetAreas (google.protobuf.Empty) returns (AreaList) {};     rpc GetAreaById (AreaId) returns (Area) {};     rpc CreateArea (AreaToCreate) returns (AreaId) {};     rpc SaveFile (File) returns (google.protobuf.Empty) {};     rpc StreamingFile (stream File) returns (google.protobuf.Empty) {}; }  message AreaId {     string id = 1; }  message AreaList {     repeated Area areas = 1; }  message Coordinate {     double longitude = 1;     double latitude = 2; }  message Area {     string id = 1;     string title = 2;     string description = 3;     string address = 4;     google.protobuf.Timestamp creationDateTime = 5;     google.protobuf.Timestamp updateDateTime = 6;     Coordinate Coordinate = 7; }  message AreaToCreate {     string title = 1;     string description = 2;     string address = 3;     Coordinate Coordinate = 4; }  message File {     string content_type = 1;     bytes content = 2; } <\/code><\/pre>\n<p>\u0411\u043b\u043e\u043a message \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 rpc \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u0445, \u0431\u043b\u043e\u043a service &#8212; \u0437\u0430 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b, \u0447\u0442\u043e \u043e\u043d\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c pom.xml, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u0438 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f.<br \/> \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>&lt;dependency&gt;     &lt;groupId&gt;io.grpc&lt;\/groupId&gt;     &lt;artifactId&gt;grpc-stub&lt;\/artifactId&gt;     &lt;version&gt;${grpc.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt;     &lt;groupId&gt;io.grpc&lt;\/groupId&gt;     &lt;artifactId&gt;grpc-protobuf&lt;\/artifactId&gt;     &lt;version&gt;${grpc.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt;     &lt;!-- Java 9+ compatibility - Do NOT update to 2.0.0 --&gt;     &lt;groupId&gt;jakarta.annotation&lt;\/groupId&gt;     &lt;artifactId&gt;jakarta.annotation-api&lt;\/artifactId&gt;     &lt;version&gt;1.3.5&lt;\/version&gt;     &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u0411\u043b\u043e\u043a build \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>&lt;build&gt;     &lt;extensions&gt;         &lt;extension&gt;             &lt;groupId&gt;kr.motd.maven&lt;\/groupId&gt;             &lt;artifactId&gt;os-maven-plugin&lt;\/artifactId&gt;             &lt;version&gt;1.7.0&lt;\/version&gt;         &lt;\/extension&gt;     &lt;\/extensions&gt;      &lt;plugins&gt;         &lt;plugin&gt;             &lt;groupId&gt;org.xolstice.maven.plugins&lt;\/groupId&gt;             &lt;artifactId&gt;protobuf-maven-plugin&lt;\/artifactId&gt;             &lt;version&gt;${protobuf-plugin.version}&lt;\/version&gt;             &lt;configuration&gt;                 &lt;protocArtifact&gt;com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}&lt;\/protocArtifact&gt;                 &lt;pluginId&gt;grpc-java&lt;\/pluginId&gt;                 &lt;pluginArtifact&gt;io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}&lt;\/pluginArtifact&gt;                 &lt;protoSourceRoot&gt;${basedir}\/src\/main\/proto\/&lt;\/protoSourceRoot&gt;             &lt;\/configuration&gt;             &lt;executions&gt;                 &lt;execution&gt;                     &lt;goals&gt;                         &lt;goal&gt;compile&lt;\/goal&gt;                         &lt;goal&gt;compile-custom&lt;\/goal&gt;                     &lt;\/goals&gt;                 &lt;\/execution&gt;             &lt;\/executions&gt;         &lt;\/plugin&gt;     &lt;\/plugins&gt; &lt;\/build&gt; <\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u043a\u0430\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u0449\u0438\u043a Maven.<\/p>\n<pre><code>&lt;groupId&gt;ru.acgnn.grpc&lt;\/groupId&gt; &lt;artifactId&gt;grpc-interface&lt;\/artifactId&gt; &lt;version&gt;1.0.0&lt;\/version&gt; <\/code><\/pre>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/xr\/d-\/b7\/xrd-b7qhiyrerinx6ew2pywix4a.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/xr\/d-\/b7\/xrd-b7qhiyrerinx6ew2pywix4a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/xr\/d-\/b7\/xrd-b7qhiyrerinx6ew2pywix4a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0441\u0431\u043e\u0440\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Java \u043a\u043b\u0430\u0441\u0441\u044b.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/u0\/eg\/gm\/u0eggmairixi6llphpxhysyf1ae.png\" alt=\"\u0421\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Java \u043a\u043b\u0430\u0441\u0441\u044b\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/u0\/eg\/gm\/u0eggmairixi6llphpxhysyf1ae.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/u0\/eg\/gm\/u0eggmairixi6llphpxhysyf1ae.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Java \u043a\u043b\u0430\u0441\u0441\u044b<\/figcaption><\/div>\n<\/figure>\n<h4>area-server<\/h4>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f grpc \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432.<br \/> \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>&lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;ru.acgnn.grpc&lt;\/groupId&gt; &lt;artifactId&gt;grpc-interface&lt;\/artifactId&gt; &lt;version&gt;1.0.0&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-oauth2-resource-server&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-validation&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.postgresql&lt;\/groupId&gt; &lt;artifactId&gt;postgresql&lt;\/artifactId&gt; &lt;scope&gt;runtime&lt;\/scope&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt; &lt;artifactId&gt;lombok&lt;\/artifactId&gt; &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.hibernate&lt;\/groupId&gt; &lt;artifactId&gt;hibernate-spatial&lt;\/artifactId&gt; &lt;version&gt;${hibernate.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt; &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt; &lt;artifactId&gt;mapstruct&lt;\/artifactId&gt; &lt;version&gt;${mapstruct.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt; &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt; &lt;artifactId&gt;mapstruct-processor&lt;\/artifactId&gt; &lt;version&gt;${mapstruct.version}&lt;\/version&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438. \u0412 \u043f\u0430\u043a\u0435\u0442\u0435 grpc \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code>import java.util.UUID;  import org.springframework.security.access.prepost.PreAuthorize;  import com.google.protobuf.Empty;  import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.server.service.GrpcService; import ru.acgnn.area_server.mapper.AreaMapper; import ru.acgnn.area_server.service.AreaService; import ru.acgnn.area_server.service.FileService; import ru.acgnn.grpc.Area; import ru.acgnn.grpc.AreaId; import ru.acgnn.grpc.AreaList; import ru.acgnn.grpc.AreaServiceGrpc.AreaServiceImplBase; import ru.acgnn.grpc.AreaToCreate; import ru.acgnn.grpc.File;  @GrpcService @RequiredArgsConstructor @PreAuthorize(\"hasRole('admin')\") public class AreaGrpc extends AreaServiceImplBase {      private final AreaService areaService;     private final FileService fileService;     private final AreaMapper areaMapper;      @Override     public void getAreaById(AreaId request, StreamObserver&lt;Area&gt; responseObserver) {         responseObserver.onNext(areaMapper.toDto(areaService.getById(UUID.fromString(request.getId()))));         responseObserver.onCompleted();     }      @Override     public void getAreas(Empty request, StreamObserver&lt;AreaList&gt; responseObserver) {         responseObserver.onNext(AreaList.newBuilder().addAllAreas(areaMapper.toListDto(areaService.getAll())).build());         responseObserver.onCompleted();     }      @Override     public void createArea(AreaToCreate request, StreamObserver&lt;AreaId&gt; responseObserver) {         responseObserver.onNext(             AreaId.newBuilder()                 .setId(areaService.createArea(areaMapper.toEntity(request)).getId().toString())                 .build()         );         responseObserver.onCompleted();     }          @Override     public void saveFile(File file, StreamObserver&lt;Empty&gt; responseObserver) {         fileService.saveFile(file);         responseObserver.onNext(Empty.newBuilder().build());         responseObserver.onCompleted();     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u043c AreaServiceImplBase, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043c\u043e\u0434\u0443\u043b\u0435\u043c grpc-interface, \u0438 \u0438\u0437 \u043d\u0435\u0433\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0438\u043c\u043f\u043e\u0440\u0442 \u043d\u0443\u0436\u043d\u044b\u0445 \u043d\u0430\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0435\u0442\u0441\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430: repository -&gt; service -&gt; mapper -&gt; controller. \u0422\u043e \u0435\u0441\u0442\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u0430 \u0432 \u043e\u0442\u0432\u0435\u0442 grpc \u0440\u0443\u0447\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0430\u043f\u043f\u0435\u0440\u0430 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0432 \u043d\u0443\u0436\u043d\u044b\u0439 dto-\u043a\u043b\u0430\u0441\u0441.<\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c.<\/p>\n<pre><code>import java.util.List; import java.util.UUID;  import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;  import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import ru.acgnn.area_server.exception.ApiServiceException; import ru.acgnn.area_server.model.entity.AreaEntity; import ru.acgnn.area_server.repository.AreaRepository;  @Slf4j @Service @RequiredArgsConstructor public class AreaService {      private final AreaRepository areaRepo;      public AreaEntity getById(UUID id) {         return areaRepo.findById(id)             .orElseThrow(() -&gt; new ApiServiceException(\"\u041f\u043b\u043e\u0449\u0430\u0434\u043a\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430\", HttpStatus.NOT_FOUND));     }      @Transactional     public AreaEntity createArea(AreaEntity area) {         if (areaRepo.existsByTitleOrCoordinateOrAddress(area.getTitle(), area.getCoordinate(), area.getAddress())) {             throw new ApiServiceException(\"\u0422\u0430\u043a\u0430\u044f \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\", HttpStatus.CONFLICT);         }         return areaRepo.save(area);     }      public List&lt;AreaEntity&gt; getAll() {         return areaRepo.findAll();     } } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 Mapper:<\/p>\n<pre><code>import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.List;  import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.PrecisionModel; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; import org.mapstruct.Named; import org.mapstruct.NullValuePropertyMappingStrategy;  import com.google.protobuf.Timestamp;  import ru.acgnn.grpc.Area; import ru.acgnn.grpc.AreaToCreate; import ru.acgnn.grpc.Coordinate; import ru.acgnn.area_server.model.entity.AreaEntity;  @Mapper(     componentModel = MappingConstants.ComponentModel.SPRING,     nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE ) public interface AreaMapper {      @Mapping(source = \"area.creationDateTime\", target = \"creationDateTime\", qualifiedByName = \"toTimestamp\")     @Mapping(source = \"area.updateDateTime\", target = \"updateDateTime\", qualifiedByName = \"toTimestamp\")     @Mapping(source = \"area.coordinate\", target = \"coordinate\", qualifiedByName = \"toCoordinate\")     Area toDto(AreaEntity area);      @Mapping(source = \"area.coordinate\", target = \"coordinate\", qualifiedByName = \"toPoint\")     AreaEntity toEntity(AreaToCreate area);      List&lt;Area&gt; toListDto(List&lt;AreaEntity&gt; areas);      @Named(\"toTimestamp\")     default Timestamp toTimestamp(LocalDateTime dateTime) {         return Timestamp.newBuilder()             .setSeconds(dateTime.atZone(ZoneId.of(\"Europe\/Moscow\")).toEpochSecond())             .build();     }      @Named(\"toCoordinate\")     default Coordinate toCoordinate(Point coordinate) {         return Coordinate.newBuilder()             .setLatitude(coordinate.getY())             .setLongitude(coordinate.getX())             .build();     }      @Named(\"toLocalDateTime\")     default LocalDateTime toLocalDateTime(Timestamp timestamp) {         return Instant             .ofEpochSecond(timestamp.getSeconds())             .atZone(ZoneId.of(\"Europe\/Moscow\"))             .toLocalDateTime();     }      @Named(\"toPoint\")     default Point toPoint(Coordinate coordinate) {         GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);         return geometryFactory.createPoint(new org.locationtech.jts.geom.Coordinate(coordinate.getLongitude(), coordinate.getLatitude()));     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 mapstruct \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 interface-\u043a\u043b\u0430\u0441\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0421omponent \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code>import org.springframework.http.HttpStatus;  import lombok.Getter;  @Getter public class ApiServiceException extends RuntimeException {      private final HttpStatus status;      public ApiServiceException(String message, HttpStatus status) {         super(message);         this.status = status;     } } <\/code><\/pre>\n<p>\u041c\u043e\u0439 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043e\u0448\u0438\u0431\u043a\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441, \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Controller Advice \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u043e\u0448\u0438\u0431\u043a\u0438 \u0441 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438.<\/p>\n<pre><code>import org.springframework.http.HttpStatus; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;  import io.grpc.Status; import lombok.extern.slf4j.Slf4j; import net.devh.boot.grpc.server.advice.GrpcAdvice; import net.devh.boot.grpc.server.advice.GrpcExceptionHandler; import ru.acgnn.area_server.exception.ApiServiceException;  @Slf4j @GrpcAdvice public class GprcHandler {      @GrpcExceptionHandler(ApiServiceException.class)     public Status handleInvalidArgument(ApiServiceException e) {         log.debug(\"ApiServiceException: {}\", e.getMessage());         return getStatus(e.getStatus()).withDescription(e.getMessage());     }      @GrpcExceptionHandler(InvalidBearerTokenException.class)     public Status handleInvalidBearerTokenException(InvalidBearerTokenException e) {         log.debug(\"InvalidBearerTokenException: {}\", e.getMessage());         return Status.UNAUTHENTICATED.withDescription(e.getMessage());     }      @GrpcExceptionHandler(IllegalArgumentException.class)     public Status handleIllegalArgumentException(IllegalArgumentException e) {         log.debug(\"IllegalArgumentException: {}\", e.getMessage());         return Status.INVALID_ARGUMENT.withDescription(e.getMessage());     }      private Status getStatus(HttpStatus status) {         return switch (status) {             case NOT_FOUND -&gt; Status.NOT_FOUND;             case BAD_REQUEST -&gt; Status.INVALID_ARGUMENT;             case CONFLICT -&gt; Status.ALREADY_EXISTS;             case FORBIDDEN -&gt; Status.PERMISSION_DENIED;             case UNAUTHORIZED -&gt; Status.UNAUTHENTICATED;             case SERVICE_UNAVAILABLE -&gt; Status.UNAVAILABLE;             default -&gt; Status.INTERNAL;         };     } } <\/code><\/pre>\n<p>\u041f\u0440\u0438\u0448\u043b\u0430 \u0438\u0434\u0435\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 HttpStatus \u0441 GrpsStatus \u0441 \u043f\u043e\u043c\u043e\u0449\u044c switch-case. \u041d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0435\u0430\u0442\u0438\u0432\u043d\u043e, \u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e! \u042d\u0442\u043e\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f gRPC \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432, \u0434\u043b\u044f HTTP \u0440\u0443\u0447\u0435\u043a \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0431\u0443\u0434\u0435\u0442 \u043b\u0443\u0447\u0448\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 handler-\u043a\u043b\u0430\u0441\u0441, \u0430\u043d\u043d\u043e\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 <a class=\"mention\" href=\"\/users\/RestControllerAdvice\">@RestControllerAdvice<\/a>.<\/p>\n<pre><code>import java.time.LocalDateTime; import java.util.Objects; import java.util.UUID;  import org.hibernate.annotations.Comment; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.proxy.HibernateProxy; import org.locationtech.jts.geom.Point;  import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter;  @Entity @Getter @Setter @Builder @Table(     name = \"area\",      uniqueConstraints = {         @UniqueConstraint(name = \"unique_area\", columnNames = { \"title\", \"address\", \"coordinate\" })     } ) @NoArgsConstructor @AllArgsConstructor public class AreaEntity {      @Id     @Column(name = \"id\")     @Comment(\"ID \u0437\u0430\u043f\u0438\u0441\u0438\")     @GeneratedValue(strategy = GenerationType.UUID)     private UUID id;      @CreationTimestamp     @Column(name = \"creation_date_time\", nullable = false, updatable = false)     @Comment(\"\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438\")     private LocalDateTime creationDateTime;      @UpdateTimestamp     @Column(name = \"update_date_time\", nullable = false)     @Comment(\"\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438\")     private LocalDateTime updateDateTime;      @NotNull     @Comment(\"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438\")     @Column(name = \"title\")     private String title;      @NotNull     @Comment(\"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438\")     @Column(name = \"description\", columnDefinition = \"text\")     private String description;      @NotNull     @Comment(\"\u0410\u0434\u0440\u0435\u0441\u0441 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438\")     @Column(name = \"address\")     private String address;      @NotNull     @Column(name = \"coordinate\")     @Comment(\"\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438\")     private Point coordinate;      @Override      public final boolean equals(Object o) {          if (this == o) return true;         if (o == null) return false;         Class&lt;?&gt; oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();          Class&lt;?&gt; thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();          if (thisEffectiveClass != oEffectiveClass) return false;          AreaEntity area = (AreaEntity) o;          return getId() != null &amp;&amp; Objects.equals(getId(), area.getId());      }           @Override      public final int hashCode() {          return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();      } } <\/code><\/pre>\n<p>\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043e\u0441\u043e\u0431\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0435\u0439 \u0443\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.<\/p>\n<p>\u0412 application.properties \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<pre><code># Service properties spring.application.name=area-server server.port=0 server.servlet.context-path=\/  # Discovery client properties eureka.client.service-url.default-zone=http:\/\/localhost:8761\/eureka  # gRPC-server properties grpc.server.port=0 <\/code><\/pre>\n<p>\u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u043f\u043e \u0435\u0433\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e, \u0430 \u043d\u0435 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 \u0438 \u043f\u043e\u0440\u0442\u0443.<\/p>\n<p>\u0422\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/mg\/ta\/za\/mgtaza-ns-elefn5pjy84nrt_t8.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 area-server\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/mg\/ta\/za\/mgtaza-ns-elefn5pjy84nrt_t8.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/mg\/ta\/za\/mgtaza-ns-elefn5pjy84nrt_t8.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 area-server<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u043a\u0430\u043a \u043d\u0430 grpc-server&#8217;\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h4>area-client<\/h4>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a gRPC-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>&lt;dependency&gt; &lt;groupId&gt;org.springdoc&lt;\/groupId&gt; &lt;artifactId&gt;springdoc-openapi-starter-webmvc-ui&lt;\/artifactId&gt; &lt;version&gt;${springdoc.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt; &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-oauth2-resource-server&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt; &lt;artifactId&gt;lombok&lt;\/artifactId&gt; &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt;  &lt;!-- \u041d\u0430\u0448 gRPC-interface --&gt; &lt;dependency&gt; &lt;groupId&gt;ru.acgnn.grpc&lt;\/groupId&gt; &lt;artifactId&gt;grpc-interface&lt;\/artifactId&gt; &lt;version&gt;1.0.0&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt; &lt;artifactId&gt;mapstruct&lt;\/artifactId&gt; &lt;version&gt;${mapstruct.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt; &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u0412 application.properties \u0443\u043a\u0430\u0436\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/p>\n<pre><code># Discovery client properties eureka.client.service-url.default-zone=http:\/\/localhost:8761\/eureka  grpc.client.area.address=discovery:\/\/\/area-server grpc.client.area.negotiation-type=plaintext grpc.client.area.enable-keep-alive=true <\/code><\/pre>\n<p>grpc.client.area.address &#8212; \u0432 \u044d\u0442\u043e\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c &#171;area&#187; \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 discovery-server (Eureka Server).<\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/tl\/h1\/vz\/tlh1vzxtmgksxzoxlm5vpr34ass.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 area-client\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/tl\/h1\/vz\/tlh1vzxtmgksxzoxlm5vpr34ass.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/tl\/h1\/vz\/tlh1vzxtmgksxzoxlm5vpr34ass.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 area-client<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a grpc-server&#8217;\u0443:<\/p>\n<pre><code>import java.io.IOException; import java.util.UUID;  import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile;  import com.google.protobuf.ByteString; import com.google.protobuf.Empty;  import io.grpc.CallCredentials; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.devh.boot.grpc.client.inject.GrpcClient; import net.devh.boot.grpc.client.security.CallCredentialsHelper; import ru.acgnn.area_client.mapper.ApiMapper; import ru.acgnn.grpc.Area; import ru.acgnn.grpc.AreaId; import ru.acgnn.grpc.AreaList; import ru.acgnn.grpc.AreaServiceGrpc.AreaServiceBlockingStub; import ru.acgnn.grpc.AreaToCreate; import ru.acgnn.grpc.File;  @Slf4j @Service @RequiredArgsConstructor public class ApiService {      @GrpcClient(\"area\")     private AreaServiceBlockingStub grpcClient;     private final ApiMapper apiMapper;      public Area getById(UUID id) {         return grpcClient             .withCallCredentials(bearerAuth())             .getAreaById(AreaId.newBuilder().setId(id.toString()).build());     }      public AreaList getAll() {         return grpcClient             .withCallCredentials(bearerAuth())             .getAreas(Empty.getDefaultInstance());     }          public UUID create(AreaToCreate area, MultipartFile file) {         try {             grpcClient                 .withCallCredentials(bearerAuth())                 .saveFile(                     File.newBuilder()                         .setContent(ByteString.copyFrom(file.getBytes(), 100, file.getBytes().length))                         .setContentType(file.getContentType())                         .build()                 );         } catch (IOException e) {             log.debug(\"IOException: {}\", e.getMessage());         }         return UUID.fromString(grpcClient             .withCallCredentials(bearerAuth())             .createArea(area)             .getId()         );     }      private CallCredentials bearerAuth() {         JwtAuthenticationToken token = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();         return CallCredentialsHelper.bearerAuth(() -&gt; token.getToken().getTokenValue());     } } <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a class=\"mention\" href=\"\/users\/GrpcClient\">@GrpcClient<\/a> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043b\u0435\u0433\u043a\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 gRPC-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u0438 \u0443\u043a\u0430\u0437\u0430\u0432 \u0438\u043c\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432 Eureka Server. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \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 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 withCallCredentials() \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0442\u043e\u043a\u0435\u043d \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0437 SecurityContextHolder, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 JwtAuthenticationToken. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c gRPC, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f OAuth 2.0 JWT.<\/p>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 create() \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f (AreaToCreate), \u0442\u0430\u043a \u0438 \u0444\u0430\u0439\u043b (MultipartFile). \u0424\u0430\u0439\u043b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 ByteString \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c MIME-\u0442\u0438\u043f\u0430, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0438\u0431\u043a\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 gRPC-\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u043d\u0435 \u0437\u0430\u0431\u043e\u0442\u044f\u0441\u044c \u043e \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430.<\/p>\n<h3>\u0418\u0442\u043e\u0433<\/h3>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043d\u0430 Java \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Boot, Spring Cloud \u0438 \u0442.\u0434., \u0433\u0434\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f gRPC. \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f \u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0432\u044b\u0436\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435, \u0431\u0435\u0437 \u0432\u043e\u0434\u044b, \u0434\u0435\u043b\u0430\u044f \u0443\u043f\u043e\u0440 \u043d\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 gRPC \u0432 \u043d\u0430\u0448\u0438 Spring Boot \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443, \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c OAuth2.0 \u0432 \u043d\u0430\u0448 gRPC-\u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<blockquote>\n<p>P.S. \u042d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f, \u043d\u0435 \u0441\u0443\u0434\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u0433\u043e. \u041e\u0447\u0435\u043d\u044c \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0438 \u043f\u043e\u043c\u043e\u0447\u044c \u0412\u0430\u043c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445, \u0435\u0441\u043b\u0438 \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><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\/ru\/articles\/910092\/\"> https:\/\/habr.com\/ru\/articles\/910092\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043c\u0438\u0440\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u0434\u0430 \u0432 \u0431\u044b\u0441\u0442\u0440\u043e\u043c \u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u043a\u0430\u043a \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 Rest API \u043a \u043d\u0430\u043c \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 gRPC. \u0421\u0442\u0430\u0442\u044c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 gRPC \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Boot \u0438 Java 17, \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0442\u0435\u043c, \u043a\u0442\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0441\u0432\u043e\u0451 \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u043e \u0441 gRPC.<\/p>\n<h3>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0442\u0435\u043e\u0440\u0438\u0438<\/h3>\n<figure class=\"\">\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432<\/figcaption><\/div>\n<\/figure>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 gRPC?<\/h4>\n<p>gRPC (Google Remote Procedure Calls) &#8212; \u044d\u0442\u043e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b (RPC) \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f IT-\u0433\u0438\u0433\u0430\u043d\u0442\u043e\u043c Google. \u0414\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b HTTP\/2, \u0430 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Protocol Buffers. \u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u0438\u043c\u0438 \u044f\u0437\u044b\u043a\u0430\u043c\u0438, \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a: Java, C++, Python \u0438 \u0434\u0440\u0443\u0433\u0438\u0435. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u0432 <a href=\"https:\/\/grpc.io\/docs\/\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 gRPC<\/a>.<\/p>\n<h3>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430<\/h3>\n<ol>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u2013 \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e HTTP\/2 \u0438 protobuf, gRPC \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0438 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043d\u0443\u044e \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u043e\u0433\u0430\u044f \u0442\u0438\u043f\u0438\u0437\u0430\u0446\u0438\u044f \u2013 \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 protobuf \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u0440\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u2013 \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u044f\u0437\u044b\u043a\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u0445, \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u0443\u043f\u0440\u043e\u0449\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u2013 gRPC \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442, \u043d\u043e \u0438 \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043b\u043d\u044b\u0439 \u0434\u0443\u043f\u043b\u0435\u043a\u0441, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0433\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0447\u0430\u0442\u0430\u0445 \u0438\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043e\u0434\u0430 \u2013 gRPC \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 (stubs), \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0441\u043d\u0438\u0436\u0430\u044f \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a. \u042d\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/li>\n<\/ol>\n<h3>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/h3>\n<ol>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u043e\u0440\u043e\u0433 \u0432\u0445\u043e\u0434\u0430 \u2013 \u0414\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 gRPC \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0438\u0437-\u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f protobuf \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP\/2. \u041e\u0434\u043d\u0430\u043a\u043e \u0441 \u043e\u043f\u044b\u0442\u043e\u043c \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0449\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 \u2013 \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 gRPC \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a gRPC-Web \u0438\u043b\u0438 \u043f\u0440\u043e\u043a\u0441\u0438-\u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u0447\u0442\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043e\u0442 Protocol Buffers \u2013 \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 protobuf \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043f\u0440\u0438\u0432\u044b\u043a \u043a JSON \u0438\u043b\u0438 XML. \u0425\u043e\u0442\u044f protobuf \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u0435\u043d, \u043e\u043d \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u2013 \u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 gRPC \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 HTTP\/2 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0435\u0441\u043b\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043f\u043e\u0434 HTTP\/2.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 Protocol Buffers<\/h3>\n<p>ProtoBuf \u2014 \u044d\u0442\u043e \u044f\u0437\u044b\u043a \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0435 Google. \u041e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 ProtoBuf \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .proto. \u042d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043a\u043b\u0430\u0441\u0441\u0430\u043c \u0432 \u041e\u041e\u041f) \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e). \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/protobuf.dev\/overview\/\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0412\u043e\u0442, \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>message Area {     string id = 1;     string title = 2;     string description = 3;     string address = 4;     google.protobuf.Timestamp creationDateTime = 5;     google.protobuf.Timestamp updateDateTime = 6;     Coordinate Coordinate = 7; } <\/code><\/pre>\n<p>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code>service AreaService {     rpc GetAreas (google.protobuf.Empty) returns (AreaList) {};     rpc GetAreaById (AreaId) returns (Area) {};     rpc CreateArea (AreaToCreate) returns (AreaId) {};     rpc SaveFile (File) returns (google.protobuf.Empty) {};     rpc StreamingFile (stream File) returns (google.protobuf.Empty) {}; } <\/code><\/pre>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 ProtoBuf<\/h4>\n<p>int32 (\u0434\u043b\u044f int) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>int64 (\u0434\u043b\u044f long) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>float \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>double \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 0<\/p>\n<p>bool \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: false<\/p>\n<p>string \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430<\/p>\n<p>byte (\u0434\u043b\u044f byte[])<\/p>\n<p>repeated (\u0434\u043b\u044f List\/Collection)<\/p>\n<p>map (\u0434\u043b\u044f Map) \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: empty map<\/p>\n<p>enum \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: \u043f\u0435\u0440\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0415\u0441\u0442\u044c \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u0430\u0441\u0441\u044b-\u043e\u0431\u0451\u0440\u0442\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a &#171;google\/protobuf\/timestamp.proto&#187; \u0434\u043b\u044f \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<h3>\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043e\u0434\u0438\u043d \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u0434\u0432\u0430 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0441 gRPC \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438:<\/p>\n<ol>\n<li>\n<p>gRPC-interface: \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 .proto \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 Java \u043a\u043b\u0430\u0441\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>gRPC-server: \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e gRPC &#171;\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432&#187; \u0438 gRPC-interface \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 Maven \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>gRPC-client: \u041b\u044e\u0431\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Java, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u043d\u0430\u0448\u0438\u043c gRPC &#171;\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c&#187;.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441 gRPC \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u043c, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<h4>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0443\u0434\u0443\u0442:<\/h4>\n<ol>\n<li>\n<p>Spring Boot<\/p>\n<\/li>\n<li>\n<p>Spring Cloud<\/p>\n<\/li>\n<li>\n<p>gRPC<\/p>\n<\/li>\n<li>\n<p>Rest API<\/p>\n<\/li>\n<li>\n<p>Swagger<\/p>\n<\/li>\n<li>\n<p>OAuth 2.0<\/p>\n<\/li>\n<li>\n<p>MapStruct<\/p>\n<\/li>\n<li>\n<p>Spring Data Jpa\/Hibernate<\/p>\n<\/li>\n<li>\n<p>PostgreSQL<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443.<\/p>\n<ol>\n<li>\n<p>Eureka Server<\/p>\n<\/li>\n<li>\n<p>API Gateway<\/p>\n<\/li>\n<li>\n<p>grpc-interface<\/p>\n<\/li>\n<li>\n<p>area-client<\/p>\n<\/li>\n<li>\n<p>area-server<\/p>\n<\/li>\n<\/ol>\n<blockquote>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c\u0441\u044f grpc-interface, area-client, area-server.<\/p>\n<\/blockquote>\n<h4>grpc-interface<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0438\u043c area.proto \u0444\u0430\u0439\u043b \u0438 \u043e\u043f\u0438\u0448\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b.<\/p>\n<pre><code>syntax = \"proto3\";  import \"google\/protobuf\/timestamp.proto\"; import \"google\/protobuf\/empty.proto\";  package ru.acgnn.grpc.area;  option java_multiple_files = true; option java_package = \"ru.acgnn.grpc\"; option java_outer_classname = \"AreaServerGrpcProto\";  service AreaService {     rpc GetAreas (google.protobuf.Empty) returns (AreaList) {};     rpc GetAreaById (AreaId) returns (Area) {};     rpc CreateArea (AreaToCreate) returns (AreaId) {};     rpc SaveFile (File) returns (google.protobuf.Empty) {};     rpc StreamingFile (stream File) returns (google.protobuf.Empty) {}; }  message AreaId {     string id = 1; }  message AreaList {     repeated Area areas = 1; }  message Coordinate {     double longitude = 1;     double latitude = 2; }  message Area {     string id = 1;     string title = 2;     string description = 3;     string address = 4;     google.protobuf.Timestamp creationDateTime = 5;     google.protobuf.Timestamp updateDateTime = 6;     Coordinate Coordinate = 7; }  message AreaToCreate {     string title = 1;     string description = 2;     string address = 3;     Coordinate Coordinate = 4; }  message File {     string content_type = 1;     bytes content = 2; } <\/code><\/pre>\n<p>\u0411\u043b\u043e\u043a message \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 rpc \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u0445, \u0431\u043b\u043e\u043a service &#8212; \u0437\u0430 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b, \u0447\u0442\u043e \u043e\u043d\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c pom.xml, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u0438 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f.<br \/> \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>&lt;dependency&gt;     &lt;groupId&gt;io.grpc&lt;\/groupId&gt;     &lt;artifactId&gt;grpc-stub&lt;\/artifactId&gt;     &lt;version&gt;${grpc.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt;     &lt;groupId&gt;io.grpc&lt;\/groupId&gt;     &lt;artifactId&gt;grpc-protobuf&lt;\/artifactId&gt;     &lt;version&gt;${grpc.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt;     &lt;!-- Java 9+ compatibility - Do NOT update to 2.0.0 --&gt;     &lt;groupId&gt;jakarta.annotation&lt;\/groupId&gt;     &lt;artifactId&gt;jakarta.annotation-api&lt;\/artifactId&gt;     &lt;version&gt;1.3.5&lt;\/version&gt;     &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u0411\u043b\u043e\u043a build \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>&lt;build&gt;     &lt;extensions&gt;         &lt;extension&gt;             &lt;groupId&gt;kr.motd.maven&lt;\/groupId&gt;             &lt;artifactId&gt;os-maven-plugin&lt;\/artifactId&gt;             &lt;version&gt;1.7.0&lt;\/version&gt;         &lt;\/extension&gt;     &lt;\/extensions&gt;      &lt;plugins&gt;         &lt;plugin&gt;             &lt;groupId&gt;org.xolstice.maven.plugins&lt;\/groupId&gt;             &lt;artifactId&gt;protobuf-maven-plugin&lt;\/artifactId&gt;             &lt;version&gt;${protobuf-plugin.version}&lt;\/version&gt;             &lt;configuration&gt;                 &lt;protocArtifact&gt;com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}&lt;\/protocArtifact&gt;                 &lt;pluginId&gt;grpc-java&lt;\/pluginId&gt;                 &lt;pluginArtifact&gt;io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}&lt;\/pluginArtifact&gt;                 &lt;protoSourceRoot&gt;${basedir}\/src\/main\/proto\/&lt;\/protoSourceRoot&gt;             &lt;\/configuration&gt;             &lt;executions&gt;                 &lt;execution&gt;                     &lt;goals&gt;                         &lt;goal&gt;compile&lt;\/goal&gt;                         &lt;goal&gt;compile-custom&lt;\/goal&gt;                     &lt;\/goals&gt;                 &lt;\/execution&gt;             &lt;\/executions&gt;         &lt;\/plugin&gt;     &lt;\/plugins&gt; &lt;\/build&gt; <\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b, \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u043a\u0430\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u0449\u0438\u043a Maven.<\/p>\n<pre><code>&lt;groupId&gt;ru.acgnn.grpc&lt;\/groupId&gt; &lt;artifactId&gt;grpc-interface&lt;\/artifactId&gt; &lt;version&gt;1.0.0&lt;\/version&gt; <\/code><\/pre>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"\">\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0441\u0431\u043e\u0440\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Java \u043a\u043b\u0430\u0441\u0441\u044b.<\/p>\n<figure class=\"\">\n<div><figcaption>\u0421\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 Java \u043a\u043b\u0430\u0441\u0441\u044b<\/figcaption><\/div>\n<\/figure>\n<h4>area-server<\/h4>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f grpc \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432.<br \/> \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>&lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;ru.acgnn.grpc&lt;\/groupId&gt; &lt;artifactId&gt;grpc-interface&lt;\/artifactId&gt; &lt;version&gt;1.0.0&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-oauth2-resource-server&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-validation&lt;\/artifactId&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.postgresql&lt;\/groupId&gt; &lt;artifactId&gt;postgresql&lt;\/artifactId&gt; &lt;scope&gt;runtime&lt;\/scope&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt; &lt;artifactId&gt;lombok&lt;\/artifactId&gt; &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.hibernate&lt;\/groupId&gt; &lt;artifactId&gt;hibernate-spatial&lt;\/artifactId&gt; &lt;version&gt;${hibernate.version}&lt;\/version&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt; &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt;  &lt;dependency&gt; &lt;groupId&gt;org.mapstruct&lt;\/groupId&gt; &lt;artifactId&gt;mapstruct&lt;\/artifactId&gt; &lt;version&gt;${mapstruct.version}&lt;\/version&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-459985","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/459985","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=459985"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/459985\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=459985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=459985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=459985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}