{"id":401965,"date":"2024-06-29T16:12:12","date_gmt":"2024-06-29T16:12:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=401965"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T16:12:12","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=401965","title":{"rendered":"<span>\u041f\u0440\u043e\u0449\u0430\u0439, Grails. \u041f\u0440\u0438\u0432\u0435\u0442, Micronaut. \u041e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435<\/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<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7fe\/e58\/9e7\/7fee589e7118eaaeeec7cbf9cb3eb42d.png\" width=\"780\" height=\"439\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7fe\/e58\/9e7\/7fee589e7118eaaeeec7cbf9cb3eb42d.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0442\u0440\u0435\u0442\u044c\u044f \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0438\u0437 \u0446\u0438\u043a\u043b\u0430 \u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0437 Grails \u0432 Micronaut.\u00a0<em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435:<\/em>\u00a0\u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u0432 Grails 4.x \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438<em>.<\/em><\/p>\n<p>\u0412\u0441\u0435\u0433\u043e \u0432 \u0446\u0438\u043a\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0439 \u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0437 Grails \u0432 Micronaut 10 \u0447\u0430\u0441\u0442\u0435\u0439:<\/p>\n<p>\u041c\u043d\u043e\u0433\u043e\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442<br \/>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<br \/>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f<br \/>\u0414\u0430\u0442\u0430\u0441\u0435\u0442\u044b<br \/>\u041c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433<br \/>\u041a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<br \/>\u0421\u0435\u0440\u0432\u0438\u0441\u044b<br \/>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<br \/>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut<br \/>Micronaut Data<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 Micronaut, Micronaut Data.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e (\u043e \u043c\u043d\u043e\u0433\u043e\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438) \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c\u00a0<a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/593895\/\"><strong>\u0437\u0434\u0435\u0441\u044c.<\/strong><\/a><\/p>\n<p>\u0412\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e (\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430\u0445, \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0435 \u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438) \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/593965\/\"><strong>\u0442\u0443\u0442.<\/strong> <\/a><\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8a2\/a6d\/822\/8a2a6d822c533c2fe3252c768d0116f9.png\" width=\"512\" height=\"347\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8a2\/a6d\/822\/8a2a6d822c533c2fe3252c768d0116f9.png\"\/><figcaption><\/figcaption><\/figure>\n<h2>\u0427\u0430\u0441\u0442\u044c 7. \u0421\u0435\u0440\u0432\u0438\u0441\u044b<\/h2>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043c\u044b \u0443\u0436\u0435 \u0438\u0437\u0432\u043b\u0435\u043a\u043b\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u043f\u043e\u0434\u043f\u0440\u043e\u0435\u043a\u0442. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails. \u041d\u0435 \u0431\u0443\u0434\u0435\u043c \u043c\u0443\u0434\u0440\u0438\u0442\u044c \u0441 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0437\u043e\u0432\u0435\u043c \u044d\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>-core<\/code>.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043f\u0430\u043f\u043a\u0443 <code>hello-core<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>libs<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0435 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-core.gradle<\/code>.<\/p>\n<pre><code class=\"java\">dependencies {     api project(':hello-data')      annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor \"io.micronaut:micronaut-inject-java\"     annotationProcessor \"io.micronaut:micronaut-validation\"      implementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")      implementation \"io.micronaut:micronaut-core\"     implementation \"io.micronaut:micronaut-inject\"     implementation \"io.micronaut:micronaut-validation\"     implementation \"io.micronaut:micronaut-runtime\"      compileOnly \"io.micronaut:micronaut-inject-groovy\"      testImplementation project(\":hello-data-test-data\")      testImplementation(\"org.spockframework:spock-core\") {         exclude group: \"org.codehaus.groovy\", module: \"groovy-all\"     }      testImplementation \"io.micronaut:micronaut-inject-groovy\"     testImplementation \"io.micronaut.test:micronaut-test-spock\" }  tasks.withType(JavaExec) {     classpath += configurations.developmentOnly     jvmArgs('-noverify', '-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') }  tasks.withType(JavaCompile){     options.encoding = \"UTF-8\"     options.compilerArgs.add('-parameters') }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0438\u0445 \u0432 \u0444\u0430\u0439\u043b <code>hello-core.gradle<\/code>.<\/p>\n<p>\u0418\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432<\/p>\n<ul>\n<li>\n<p><code>src\/main\/groovy<\/code><\/p>\n<\/li>\n<li>\n<p><code>grails-app\/services<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0432 \u043f\u0430\u043f\u043a\u0443 <code>src\/main\/groovy<\/code> \u043d\u043e\u0432\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<pre><code>implementation project(':hello-core')<\/code><\/pre>\n<p>\u0411\u0438\u043d\u044b Micronaut \u043b\u0443\u0447\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Grails, \u0433\u0434\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f <code>FieldByName<\/code>.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 Grails:<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.VehicleDataService  @CompileStatic class VehicleService {      VehicleDataService vehicleDataService      \/\/ methods  }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043c\u044b \u0432\u043d\u0435\u0434\u0440\u044f\u0435\u043c \u043f\u043e \u0438\u043c\u0435\u043d\u0438 <code>VehicleDataService<\/code> \u0432 <code>VehicleService<\/code> \u0432 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>vehicleDataService<\/code>. \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0433\u0440\u0430\u0435\u0442 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0430\u0436\u043d\u0443\u044e \u0440\u043e\u043b\u044c \u0432 Grails.<\/p>\n<p>\u041c\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0438\u0437 <code>hello\/grails-app\/services<\/code> \u0432 <code>hello-core\/src\/main\/groovy<\/code>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/030\/1ce\/fa6\/0301cefa6ebd72b49286a7933ad69878.png\" width=\"779\" height=\"890\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/030\/1ce\/fa6\/0301cefa6ebd72b49286a7933ad69878.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0435\u0433\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 \u0431\u0438\u043d Micronaut<\/p>\n<p>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0432 Micronaut \u0445\u043e\u0442\u044c \u0438 \u0434\u043b\u0438\u043d\u043d\u0435\u0435, \u0437\u0430\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>javax.inject.Singleton<\/code>, \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u043f\u043e\u043b\u044f \u043a\u0430\u043a private final \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0438\u0445 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435.<\/p>\n<p>\u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0438\u043c\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u043d\u043e\u0433\u043e \u0431\u0438\u043d\u0430 \u0443\u0436\u0435 \u043d\u0438 \u043d\u0430 \u0447\u0442\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442, \u0434\u0430 \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 Micronaut \u0431\u043e\u0433\u0430\u0447\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 Grails.<\/p>\n<p>\u0412\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 Grails. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043b\u0438\u0448\u044c \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@Inject<\/code> \u043f\u0435\u0440\u0435\u0434 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u043b\u044f.<\/p>\n<pre><code class=\"java\">class VehicleController {          @Inject VehicleService vehicleService          \/\/ controller actions  }<\/code><\/pre>\n<h3>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f Micronaut Grails<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 Grails \u0438\u0437 \u0431\u0438\u043d\u043e\u0432 Micronaut \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f GORM, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c Micronaut. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>GrailsApp<\/code> \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 Micronaut, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/agorapulse.github.io\/micronaut-grails\/\"><u>Micronaut Grails<\/u><\/a>:<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Grails Integration for Micronaut<\/span><\/div>\n<p><a href=\"https:\/\/agorapulse.github.io\/micronaut-grails\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">agorapulse.github.io<\/a><\/div>\n<\/div>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u0434\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails\u00a0\u2014 <code>hello.gradle<\/code>:<\/p>\n<pre><code>implementation 'com.agorapulse:micronaut-grails:3.0.7' implementation 'com.agorapulse:micronaut-grails-web-boot:3.0.7'<\/code><\/pre>\n<p>\u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043d\u0443\u0436\u043d\u043e <strong>\u0443\u0434\u0430\u043b\u0438\u0442\u044c<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code>compile \"org.grails:grails-web-boot\"<\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441 <code>Application<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"java\">import com.agorapulse.micronaut.grails.MicronautGrailsApp import com.agorapulse.micronaut.grails.MicronautGrailsAutoConfiguration  import groovy.transform.CompileStatic import hello.legacy.Vehicle  @CompileStatic class Application extends MicronautGrailsAutoConfiguration {      final Collection&lt;Package> packages = [             Vehicle.package,     ]      static void main(String[] args) {         MicronautGrailsApp.run(Application, args)     }  }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 <code>MicronautGrailsAutoConfiguration<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>MicronautGrailsApp<\/code> \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0415\u0449\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0427\u0442\u043e\u0431\u044b \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0431\u0440\u0438\u043a\u0443, \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0449\u0443\u044e \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.VehicleDataService import io.micronaut.context.annotation.Bean import io.micronaut.context.annotation.Factory import spock.mock.DetachedMockFactory  import javax.inject.Singleton  @Factory @CompileStatic class MockDataServicesFactory {      @Bean     @Singleton     VehicleDataService vehicleDataService() {         return new DetachedMockFactory().Mock(VehicleDataService)     }  }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <code>Autowire<\/code> \u0432 Spring \u0438 <code>AutowiredTest<\/code> \u0432 Grail. \u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f <code>AutoAttach<\/code> \u0438\u0437 Spock \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d \u043a \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"java\">import com.agorapulse.dru.Dru import com.agorapulse.gru.Gru import com.agorapulse.gru.grails.Grails import com.fasterxml.jackson.databind.ObjectMapper import grails.testing.gorm.DataTest import grails.testing.spring.AutowiredTest import grails.testing.web.controllers.ControllerUnitTest import hello.legacy.Vehicle import hello.legacy.VehicleDataService import org.springframework.beans.factory.annotation.Autowired import spock.lang.AutoCleanup import spock.lang.Specification import spock.mock.AutoAttach   class VehicleControllerSpec extends Specification implements ControllerUnitTest&lt;VehicleController>, DataTest, AutowiredTest{      @AutoCleanup Dru dru = Dru.create {         include HelloDataSets.VEHICLES     }      @AutoCleanup Gru gru = Gru.create(Grails.create(this)).prepare {         include UrlMappings     }      @Autowired @AutoAttach VehicleDataService vehicleDataService      @Override     Closure doWithSpring() {         return {             objectMapper(ObjectMapper)         }     }      void 'render with gru'() {         given:             dru.load()          when:              gru.test {                 get '\/vehicle\/1'                 expect {                     json 'vehicle.json'                 }             }          then:             gru.verify()              1 * vehicleDataService.findById(1) >> dru.findByType(Vehicle)     }  }<\/code><\/pre>\n<h4>\u041f\u043b\u0430\u0433\u0438\u043d\u044b Grails \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h4>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043c\u043d\u0438\u043c\u0443\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443 \u044d\u0442\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438. \u041e\u0431\u044b\u0447\u043d\u043e \u0432\u0430\u0448\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u044b Grails, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u044b\u0441\u043a\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438 \u0434\u043b\u044f Micronaut. \u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Micronaut, Agorapulse OSS Hub \u0438\u043b\u0438 \u043a \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 Awesome Micronaut:<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/micronaut.io\/wp-content\/uploads\/2021\/02\/the-micronaut-framework.gif&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Docs &#8212; Micronaut Framework<\/span><\/div>\n<p><a href=\"https:\/\/micronaut.io\/docs\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">micronaut.io<\/a><\/div>\n<\/div>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Agorapulse OSS Hub<\/span><\/div>\n<p><a href=\"https:\/\/agorapulse.github.io\/agorapulse-oss\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">agorapulse.github.io<\/a><\/div>\n<\/div>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/opengraph.githubassets.com\/981498c4943f1529f8a1788c9cf8656326b813890b21a08e10e223b455d2da31\/JonasHavers\/awesome-micronaut&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>GitHub &#8212; JonasHavers\/awesome-micronaut: A curated list of resources for the Micronaut JVM framework<\/span><\/div>\n<p><a href=\"https:\/\/github.com\/JonasHavers\/awesome-micronaut\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">github.com<\/a><\/div>\n<\/div>\n<p>\u00a0<em>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433\u00a0\u2014 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432.<\/em><\/p>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 8. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<\/h2>\n<p>\u041d\u0430 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0435\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 Grails \u0432 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u043d\u0430 Micronaut.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 Grails.<\/p>\n<pre><code class=\"java\">import com.fasterxml.jackson.databind.ObjectMapper import groovy.transform.CompileStatic import hello.legacy.Vehicle import hello.legacy.VehicleDataService  import javax.inject.Inject  @CompileStatic class VehicleController {      @Inject ObjectMapper objectMapper     @Inject VehicleService vehicleService     @Inject VehicleDataService vehicleDataService      Object show(Long id) {         Vehicle vehicle = vehicleDataService.findById(id)         if (!vehicle) {             throw new NoSuchElementException(\"No vehicle found for id: $id\")         }         render contentType: 'application\/json', text: objectMapper.writeValueAsString(                 new VehicleResponse(                         id: vehicle.id,                         name: vehicle.name,                         make: vehicle.make,                         model: vehicle.model                 )         )     }      Object noSuchElement(NoSuchElementException e) {         render status: 404     }  }<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u0443\u0441\u043f\u0435\u0445\u043e\u043c.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 hello-api \u0432 \u043f\u0430\u043f\u043a\u0435 libs \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u0441\u0431\u043e\u0440\u043a\u0438, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 hello-api.gradle:<\/p>\n<pre><code class=\"java\"> dependencies {     api project(':hello-core')      annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor \"io.micronaut:micronaut-inject-java\"     annotationProcessor \"io.micronaut:micronaut-validation\"      implementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")      implementation \"io.micronaut:micronaut-core\"     implementation \"io.micronaut:micronaut-inject\"     implementation \"io.micronaut:micronaut-validation\"     implementation \"io.micronaut:micronaut-runtime\"     implementation \"io.micronaut:micronaut-http\"     implementation \"io.micronaut:micronaut-router\"      compileOnly \"io.micronaut:micronaut-inject-groovy\"      testAnnotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     testAnnotationProcessor \"io.micronaut:micronaut-inject-java\"     testAnnotationProcessor \"io.micronaut:micronaut-validation\"      testImplementation project(':hello-data-test-data'), {         \/\/ we'll be using pure mocks         exclude group: 'com.agorapulse', module: 'dru-client-gorm'     }      testImplementation(\"org.spockframework:spock-core\") {         exclude group: \"org.codehaus.groovy\", module: \"groovy-all\"     }      testImplementation \"io.micronaut:micronaut-inject-groovy\"     testImplementation \"io.micronaut:micronaut-http-server-netty\"     testImplementation \"io.micronaut.test:micronaut-test-spock\"      testImplementation \"com.agorapulse:gru-micronaut:0.9.2\" }  tasks.withType(JavaExec) {     classpath += configurations.developmentOnly     jvmArgs('-noverify', '-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') }  tasks.withType(JavaCompile){     options.encoding = \"UTF-8\"     options.compilerArgs.add('-parameters') }<\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 Micronaut. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u0448\u043b\u0438 \u043d\u0430 \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433 Jackson, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u043d\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043e\u0441\u043e\u0431\u043e\u0433\u043e \u0442\u0440\u0443\u0434\u0430. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439 \u0434\u043b\u044f \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.model.Vehicle import hello.legacy.model.VehicleRepository import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Get  @CompileStatic @Controller('\/vehicle') class VehicleController {      private final VehicleRepository vehicleRepository      VehicleController(VehicleRepository vehicleDataService) {         this.vehicleRepository = vehicleDataService     }      @Get('\/{id}')     Optional&lt;VehicleResponse> show(Long id) {         return vehicleRepository             .findById(id)             .map { vehicle -> toResponse(vehicle) }     }      private static VehicleResponse toResponse(Vehicle vehicle) {         return new VehicleResponse(             id: vehicle.id,             name: vehicle.name,             make: vehicle.make,             model: vehicle.model         )     } }<\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 Micronaut \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433 Jackson, \u043c\u044b \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u043c\u0441\u044f \u043e\u0442 \u044f\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f <code>objectMapper<\/code>. \u041a\u043b\u0430\u0441\u0441 <code>VehicleReponse<\/code> \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails \u0432 \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435. Micronaut \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 404 Not Found \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>Optional<\/code>, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Optional<\/code>.<\/p>\n<p>\u0412 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>\u0443\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0442\u0440\u0435\u0439\u0442\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>ControllerUnitTest<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>MicronautTest<\/code> \u043a \u043a\u043b\u0430\u0441\u0441\u0443;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 <code>Gru<\/code> \u043d\u0430 <code>@Inject Gru gru<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c id \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f POGO-\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>Dru<\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"java\">import com.agorapulse.dru.Dru import com.agorapulse.gru.Gru import hello.HelloDataSets import hello.legacy.Vehicle import hello.legacy.VehicleDataService import io.micronaut.test.annotation.MicronautTest import spock.lang.AutoCleanup import spock.lang.Specification import spock.mock.AutoAttach  import javax.inject.Inject  @MicronautTest class VehicleControllerSpec extends Specification {      @AutoCleanup Dru dru = Dru.create {         include HelloDataSets.VEHICLES     }      @Inject Gru gru      @Inject @AutoAttach VehicleDataService vehicleDataService      void 'render with gru'() {         given:             dru.load()          when:             gru.test {                 get '\/vehicle\/1'                 expect {                     json 'vehicle.json'                 }             }          then:             gru.verify()              1 * vehicleDataService.findById(1) >> dru.findByType(Vehicle).tap { id = 1 }     }  }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>MockDataServiceFactory<\/code> \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 <code>hello-api<\/code>. \u0424\u0430\u0439\u043b\u044b \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 <code>vehicle.json<\/code> \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437 \u043f\u0430\u043f\u043e\u043a <code>src\/test\/resources<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 JSON-\u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043c\u0435\u043b \u043f\u0440\u0435\u0436\u043d\u0438\u0439 \u0432\u0438\u0434.<\/p>\n<h3>\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u0430\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432\u00a0\u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0430. \u041d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0441 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a HTTP-\u0444\u0438\u043b\u044c\u0442\u0440\u044b \u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 Grails. \u041f\u043e\u0434\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 <a href=\"https:\/\/micronaut.io\/docs\/\"><u>\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043a Micronaut<\/u><\/a>:<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/micronaut.io\/wp-content\/uploads\/2021\/02\/the-micronaut-framework.gif&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Docs &#8212; Micronaut Framework<\/span><\/div>\n<p><a href=\"https:\/\/micronaut.io\/docs\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">micronaut.io<\/a><\/div>\n<\/div>\n<p><em>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u043e\u0435 <\/em><a href=\"https:\/\/medium.com\/p\/c0d3956afe47\"><em><u>\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut<\/u><\/em><\/a><em>.<\/em><\/p>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 9. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut<\/h2>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0432 \u043d\u0430\u0448\u0435\u043c \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0434\u043b\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0417\u043d\u0430\u0447\u0438\u0442, \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u043e\u043c <code>-mn<\/code> (\u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0447\u0442\u043e-\u0442\u043e \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 <code>hello-mn<\/code>) \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432 \u043f\u043e\u0434\u043f\u0430\u043f\u043a\u0443 <code>apps<\/code> \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-mn.gradle<\/code>, \u0438\u043c\u0435\u044e\u0449\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435:<\/p>\n<pre><code class=\"java\">plugins {     id 'application'     id 'com.github.johnrengelman.shadow' version '5.2.0' }  dependencies {     annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor 'io.micronaut:micronaut-inject-java'     annotationProcessor 'io.micronaut:micronaut-validation'      implementation project(':hello-api')      implementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     implementation 'io.micronaut:micronaut-http-client'     implementation 'io.micronaut:micronaut-inject'     implementation 'io.micronaut:micronaut-validation'     implementation 'io.micronaut:micronaut-runtime'     implementation 'io.micronaut:micronaut-http-server-netty'       implementation 'org.apache.logging.log4j:log4j-slf4j18-impl:2.14.1'     implementation 'mysql:mysql-connector-java:8.0.26'        compileOnly 'io.micronaut:micronaut-inject-groovy'      testAnnotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     testImplementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     testImplementation('org.spockframework:spock-core') {         exclude group: 'org.codehaus.groovy', module: 'groovy-all'     }     testImplementation 'io.micronaut:micronaut-inject-groovy'     testImplementation 'io.micronaut.test:micronaut-test-spock'     testImplementation 'io.micronaut.test:micronaut-test-junit5' }  mainClassName = 'hello.Application'  shadowJar {     mergeServiceFiles()     mergeGroovyExtensionModules() }  tasks.withType(JavaCompile){     options.encoding = 'UTF-8'     options.compilerArgs.add('-parameters') }<\/code><\/pre>\n<p>\u041f\u043e\u0434\u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u043a\u043b\u0430\u0441\u0441, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0438\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.Vehicle import io.micronaut.runtime.Micronaut  @CompileStatic class Application {      static void main(String[] args) {         Micronaut.build(args)                 .mainClass(Application)                 .packages(Vehicle.package.name)                 .start()     }  }<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u0430; \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0439\u0442\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043b\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b Docker Compose \u0438 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0443 <code>hello-mn<\/code>:<\/p>\n<pre><code class=\"java\">services:   db:     image: mariadb     restart: always     environment:       MYSQL_ROOT_PASSWORD: root       MYSQL_PASSWORD: grails       MYSQL_USER: grails       MYSQL_DATABASE: hello     ports:       - 3306:3306<\/code><\/pre>\n<p><em>\u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f MariaDB \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u043b\u0443\u0447\u0448\u0435\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043d\u044b\u043c\u0438 \u0447\u0438\u043f\u0430\u043c\u0438 Apple.<\/em><\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u043a\u0430\u043a <\/p>\n<pre><code class=\"java\">dataSource:   dbCreate: update   url: jdbc:mysql:\/\/localhost:3306\/hello?useSSL=false   driverClassName: com.mysql.cj.jdbc.Driver   dialect: org.hibernate.dialect.MySQL5InnoDBDialect   username: grails   password: grails<\/code><\/pre>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0431\u0430\u0437\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0437\u0446\u0430:<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.Vehicle import hello.legacy.VehicleDataService import io.micronaut.context.event.ApplicationEventListener import io.micronaut.runtime.event.ApplicationStartupEvent  import javax.inject.Singleton  @Singleton @CompileStatic class VehicleLoader implements ApplicationEventListener&lt;ApplicationStartupEvent> {      private final VehicleDataService vehicleDataService      VehicleLoader(VehicleDataService vehicleDataService) {         this.vehicleDataService = vehicleDataService     }      @Override     void onApplicationEvent(ApplicationStartupEvent event) {         if (vehicleDataService.findById(1) == null) {             Vehicle vehicle = new Vehicle(                     name: 'The Box',                     make: 'Citroen',                     model: 'Berlingo'             )             vehicleDataService.save(vehicle)         }     } }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>ApplicationEventListener&lt;ApplicationStartupEvent><\/code>, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0435\u0435 \u043a\u043e\u0434 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0444\u0430\u0439\u043b Docker Compose \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 <code>hello-mn<\/code>:<\/p>\n<pre><code>docker compose up -d<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code>.\/gradlew :hello-mn:run<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e cURL \u0438\u043b\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u043d\u0438\u0431\u0443\u0434\u044c HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442:<\/p>\n<pre><code>curl http:\/\/localhost:8080\/vehicle\/1 # {\"id\":1,\"name\":\"The Box\",\"make\":\"Citroen\",\"model\":\"Berlingo\"}<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0435\u0440\u0435\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0438\u043c\u0438 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<p>\u041e\u0431\u044b\u0447\u043d\u043e \u0435\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0444\u0430\u0439\u043b <code>application.groovy<\/code> \u0432 \u0432\u0438\u0434\u0435 \u0441\u0435\u0440\u0438\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 <code>application.yml<\/code>. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0431\u043b\u043e\u043a\u0438 <code>environment { ... }<\/code> \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 Micronaut\u00a0\u2014 \u0432\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0438\u0445 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b <code>application-development.yml<\/code> \u0438 <code>application-production.yml.<\/code><\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0434\u0440\u0443\u0433\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u0441\u0442\u0430\u0440\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 Grails, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0438\u0442\u0435 \u043d\u0430\u043c \u043e\u0431 \u044d\u0442\u043e\u043c. \u041c\u044b \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0441\u043b\u0443\u0447\u0430\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043a \u0441\u0442\u0430\u0442\u044c\u044f\u043c.<\/p>\n<p><em>\u0425\u043e\u0442\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u0440\u0430\u0431\u043e\u0442\u0435, \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0430\u0433\u00a0\u2014 <\/em><a href=\"https:\/\/medium.com\/p\/759c6c36bc7\/\"><em><u>\u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 GORM \u0432 Micronaut<\/u><\/em><\/a><em>.<\/em><\/p>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 10. Micronaut Data<\/h2>\n<p>\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043c\u044b \u0441\u043e\u0447\u0435\u0442\u0430\u043b\u0438 Micronaut \u0441 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438 GORM. \u0422\u0430\u043a\u0430\u044f \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f \u0434\u0430\u043b\u0435\u043a\u0430 \u043e\u0442 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439, \u043d\u043e \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439 \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0441 GORM \u043d\u0430 Micronaut Data, \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u0430\u043c\u0443\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c.<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Micronaut Data<\/span><\/div>\n<p><a href=\"https:\/\/micronaut-projects.github.io\/micronaut-data\/latest\/guide\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">micronaut-projects.github.io<\/a><\/div>\n<\/div>\n<p>Micronaut Data \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u0432\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\u00a0\u2014 Micronaut Data JPA \u0438 Micronaut Data JDBC. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0438\u0445, \u043d\u0430\u0447\u0430\u0432 \u0441 \u0431\u043e\u043b\u0435\u0435 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u043e\u0439\u00a0\u2014 Micronaut Data JDBC.<\/p>\n<h3>Micronaut Data JDBC<\/h3>\n<p>Micronaut Data JDBC \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u0434\u043b\u044f:<\/p>\n<ul>\n<li>\n<p>\u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u044c, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0436\u0443\u0440\u043d\u0430\u043b\u044b, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0441\u0432\u044f\u0437\u0435\u0439 \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>save<\/code> \u0432 Micronaut Data JDBC \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u043e\u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0417\u0434\u0435\u0441\u044c \u043d\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u0430 <code>saveOrUpdate<\/code>, \u0447\u0442\u043e \u0432\u044b\u043d\u0443\u0436\u0434\u0430\u0435\u0442 \u043d\u0430\u0441 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0443\u0436\u0435 \u0442\u0430\u043a\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>save<\/code> \u0438\u043b\u0438 <code>update<\/code>. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439, \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0441 \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043c\u0435\u0442\u043e\u0434\u044b <code>update*<\/code> \u043e\u0431\u044b\u0447\u043d\u043e \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043f\u043e\u0434\u043b\u0435\u0436\u0430\u0449\u0438\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044e.<\/p>\n<p>\u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0442\u0430\u043a\u0430\u044f \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u044c Micronaut Data JDBC \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0435 \u0440\u0430\u043d\u0435\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Micronaut Data JDBC \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u044f\u0432\u043d\u043e\u0433\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0432\u044f\u0437\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f <code>@Join<\/code>, \u0442\u043e\u0433\u0434\u0430 \u0432 \u043f\u043e\u043b\u0435 <code>author<\/code> \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0433\u043e <code>id<\/code>.<\/p>\n<pre><code class=\"java\">@JdbcRepository(dialect = Dialect.MYSQL) public interface PageRepository extends CrudRepository&lt;Page, Long> {                @Override     @Join(value = \"author\", type = Join.Type.FETCH)            Optional&lt;Page> findById(@NonNull @NotNull Long aLong); }<\/code><\/pre>\n<p>Micronaut Data JDBC \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 (optimistic locking), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445\u00a0\u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c Micronaut Data JDBC \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0443\u0437\u043a\u043e\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445. \u041e\u0431\u044b\u0447\u043d\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 Micronaut Data JPA.<\/p>\n<h3>Micronaut Data JPA<\/h3>\n<p>Micronaut Data JPA \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0442\u0435\u0441\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 GORM. \u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u0431\u043e\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043b\u0435\u0436\u0438\u0442 Hibernate \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0435\u0433\u043e \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432\u0430\u043c\u0438 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0430\u043c\u0438. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b\u00a0\u2014 \u0441\u0430\u043c\u044b\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439\u00a0\u2014 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0435\u0441\u0441\u0438\u0439, \u043b\u0435\u043d\u0438\u0432\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>Micronaut Data JPA \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u043b\u0443\u0447\u0448\u0435 \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u043d\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0442\u0430\u043a\u043e\u0439 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 ORM, \u043a\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>\u043b\u0435\u043d\u0438\u0432\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0432\u044f\u0437\u0435\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u00ab\u0433\u0440\u044f\u0437\u043d\u043e\u0439\u00bb \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 (dirty checking);<\/p>\n<\/li>\n<li>\n<p>\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0438\u0437 GORM \u0432 Micronaut Data<\/h3>\n<p>\u041a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 Micronaut Data JPA, \u0442\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 Micronaut Data JDBC \u0432\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430-\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440, \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u044e\u0449\u0430\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e.<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Grails Integration for Micronaut<\/span><\/div>\n<p><a href=\"https:\/\/agorapulse.github.io\/micronaut-grails\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">agorapulse.github.io<\/a><\/div>\n<\/div>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0443\u0444\u0444\u0438\u043a\u0441 <code>-legacy<\/code> \u043a \u0438\u043c\u0435\u043d\u0430\u043c \u043f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0435\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0441\u0431\u043e\u0440\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0430\u043f\u043a\u0430 <code>hello-data<\/code> \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432 <code>hello-data-legacy<\/code>, \u0430 \u0444\u0430\u0439\u043b <code>hello-data.gradle<\/code>\u00a0\u2014 \u0432 <code>hello-data-legacy.gradle<\/code>. \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0438\u043c\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 \u0441\u0431\u043e\u0440\u043a\u0438.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-data-legacy.gradle<\/code>:<\/p>\n<pre><code class=\"java\">sourceSets {     main {         groovy {             \/\/ the source folder for the GORM domain classes             srcDir 'grails-app\/domain'             \/\/ if you also want to include some services             srcDir 'grails-app\/services'         }     } }  dependencies {     api platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     api 'io.micronaut.configuration:micronaut-hibernate-gorm'      \/\/ GORM     compile \"org.grails:grails-datastore-gorm-hibernate5:${project['gorm.hibernate.version']}\"      \/\/ required for Grails Plugin generation     compileOnly \"org.grails:grails-core:$grailsVersion\"      \/\/ required for Micronaut service generation, if present     compileOnly \"io.micronaut:micronaut-inject-groovy:$micronautVersion\"      \/\/ required for jackson ignores generation for Micronaut     compileOnly 'com.fasterxml.jackson.core:jackson-databind:2.8.11.3'      testImplementation(\"org.spockframework:spock-core\") {         exclude group: \"org.codehaus.groovy\", module: \"groovy-all\"     }      \/\/ generator library     testImplementation 'com.agorapulse:micronaut-grails-jpa-generator:3.0.6'      \/\/ MariaDB support for Testcontainers     \/\/ more universal than MySQL as it works well even on M1 processors     testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3'     testImplementation \"org.testcontainers:mariadb:1.15.3\"      \/\/ only required for M1 processors, due issues in 1.15.3     testImplementation 'com.github.docker-java:docker-java-api:3.2.8'     testImplementation 'com.github.docker-java:docker-java-transport-zerodep:3.2.8'     testImplementation 'net.java.dev.jna:jna:5.8.0' }  test {     systemProperty 'project.root', rootDir.absolutePath }<\/code><\/pre>\n<p>\u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 JPA \u0438 Testcontainers. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043c\u044b \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>project.root<\/code>.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 <code>hello-data-legacy\/src\/test\/resources\/application-test.yml<\/code>.<\/p>\n<pre><code class=\"java\">dataSource:   dbCreate: \"create-drop\"   url: \"jdbc:tc:mariadb:10.5.10:\/\/\/test?useSSL=false\"   driverClassName: \"org.testcontainers.jdbc.ContainerDatabaseDriver\"   dialect: org.hibernate.dialect.MySQL5InnoDBDialect   username: \"username\"   password: \"password\"<\/code><\/pre>\n<p>\u0418 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c <code>MicronautGeneratorSpec<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<pre><code class=\"java\">class MicronautGeneratorSpec extends Specification {      @AutoCleanup ApplicationContext context = ApplicationContext.run()      MicronautJpaGenerator generator = new MicronautJpaGenerator(         context.getBean(HibernateDatastore),         new DefaultConstraintEvaluator()     )      void 'generate domains'() {         given:             File root = new File(System.getProperty('project.root'), 'libs\/hello-data\/src\/main\/groovy')         when:             generator.generate(root)         then:             noExceptionThrown()     }  }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u0430 \u043a\u043b\u0430\u0441\u0441\u044b \u043d\u043e\u0432\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u043f\u043a\u0435 <code>libs\/hello-data<\/code> \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>Vehicle<\/code>, \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 JPA-\u0430\u043d\u0430\u043b\u043e\u0433 \u0438 \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f:<\/p>\n<pre><code class=\"java\">import grails.gorm.annotation.Entity  @Entity class Vehicle {      String name      String make     String model      static Closure constraints = {         name maxSize: 255         make inList: ['Ford', 'Chevrolet', 'Nissan', 'Citroen']         model nullable: true     }  }<\/code><\/pre>\n<p><em>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<\/em><\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import javax.annotation.Nullable import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id import javax.persistence.Version import javax.validation.constraints.NotNull import javax.validation.constraints.Pattern import javax.validation.constraints.Size  @Entity @CompileStatic class Vehicle {      @Id @GeneratedValue(strategy = GenerationType.IDENTITY)     Long id      @Version     Long version      @NotNull     @Pattern(regexp = 'Ford|Chevrolet|Nissan|Citroen')     @Size(max = 255)     String make      @Nullable     @Size(max = 255)     String model      @NotNull     @Size(max = 255)     String name  }<\/code><\/pre>\n<p><em>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c<\/em><\/p>\n<pre><code class=\"java\">import io.micronaut.data.annotation.Repository import io.micronaut.data.repository.CrudRepository  @Repository interface VehicleRepository extends CrudRepository&lt;Vehicle, Long> {  }<\/code><\/pre>\n<p><em>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/em><\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043f\u0440\u0435\u0434\u043c\u0435\u0442 \u043f\u043e\u043c\u0435\u0442\u043e\u043a \u00abTODO\u00bb \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0435\u0441\u044c \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043c\u0435\u0441\u0442\u0435. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432\u0441\u0435, \u043d\u043e \u0432 \u0440\u0435\u0434\u043a\u0438\u0445 \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0443\u043f\u0443\u0449\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-data.gradle<\/code>:<\/p>\n<pre><code class=\"java\">dependencies {     annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor 'io.micronaut.data:micronaut-data-processor'     annotationProcessor 'io.micronaut:micronaut-inject-java'     annotationProcessor 'io.micronaut:micronaut-validation'      api platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     api 'io.micronaut.data:micronaut-data-hibernate-jpa'      api 'jakarta.persistence:jakarta.persistence-api:2.2.2'      implementation 'io.micronaut:micronaut-core'     implementation 'io.micronaut:micronaut-inject'     implementation 'io.micronaut:micronaut-validation'     implementation 'io.micronaut:micronaut-runtime'      implementation 'io.micronaut.configuration:micronaut-jdbc-tomcat'      compileOnly 'io.micronaut:micronaut-inject-groovy'     compileOnly 'io.micronaut.data:micronaut-data-processor' }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 <code>convention.groovy<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u043b \u043f\u0440\u0430\u0432\u0438\u043b\u0430 GORM \u043d\u0430 \u043d\u043e\u0432\u044b\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b:<\/p>\n<pre><code class=\"java\">Map conventions = [         disable                     : false,         whiteListScripts            : true,         disableDynamicCompile       : false,         dynamicCompileWhiteList     : [                 'UrlMappings',                 'Application',                 'BootStrap',                 'resources',                 'org.grails.cli'         ],         limitCompileStaticExtensions: false,         defAllowed                  : false,    \/\/ For controllers you can use Object in place of def, and in Domains add Closure to constraints\/mappings closure fields.         skipDefaultPackage          : true,     \/\/ For GSP files ] System.setProperty(         'enterprise.groovy.conventions',         \"conventions=${conventions.inspect()}\" )<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u043e\u0432\u044b\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>@Ingore<\/code> \u0432 <code>MicronautGeneratorSpec<\/code>, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c \u0434\u0430\u043d\u043d\u044b\u043c. \u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0435\u0441\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>hello-data-test-data<\/code> \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043f\u0430\u043f\u043a\u0443 <code>hello-data-legacy-test-data<\/code>.<\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-data-test-data.gradle<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Micronaut JPA.<\/p>\n<pre><code class=\"java\">dependencies {     api project(':hello-data')      api \"com.agorapulse:dru-client-micronaut-data:0.8.1\"     api \"com.agorapulse:dru-parser-json:0.8.1\"      compileOnly \"io.micronaut:micronaut-inject-groovy:$micronautVersion\"      testImplementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")      testImplementation \"io.micronaut:micronaut-inject-groovy:$micronautVersion\"      testImplementation \"io.micronaut.test:micronaut-test-spock\"     testImplementation(\"org.spockframework:spock-core\") {         exclude group: \"org.codehaus.groovy\", module: \"groovy-all\"     }      testImplementation 'org.apache.logging.log4j:log4j-slf4j18-impl:2.14.1'      \/\/ MariaDB support for Testcontainers     \/\/ more universal than MySQL as it works well even on M1 processors     testImplementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3'     testImplementation \"org.testcontainers:mariadb:1.15.3\"      \/\/ only required for M1 processors, due issues in 1.15.3     testImplementation 'com.github.docker-java:docker-java-api:3.2.8'     testImplementation 'com.github.docker-java:docker-java-transport-zerodep:3.2.8'     testImplementation 'net.java.dev.jna:jna:5.8.0' }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0432 \u0444\u0430\u0439\u043b\u0435 <code>src\/test\/resources\/application-test.yml<\/code>:<\/p>\n<pre><code class=\"java\">datasources:   default:     url: jdbc:tc:mariadb:10.5.10:\/\/\/test?useSSL=false&amp;TC_DAEMON=true     driverClassName: org.testcontainers.jdbc.ContainerDatabaseDriver     username: grails     password: grails     dialect: MYSQL jpa:   default:     entity-scan:       packages: 'hello.legacy.model'     properties:       hibernate:         hbm2ddl:           auto: create-drop<\/code><\/pre>\n<p>\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u0441\u0442\u0435, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u0443\u0434\u0443\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438. \u041a\u043b\u0430\u0441\u0441 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0435\u0439 <code>@MicronautTest<\/code>, \u043e\u043d \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <code>ApplicationContextProvider<\/code>, \u0432\u043d\u0435\u0434\u0440\u044f\u0435\u0442 <code>ApplicationContext<\/code> \u0438 \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<pre><code class=\"java\">import com.agorapulse.dru.Dru import hello.legacy.model.Vehicle import hello.legacy.model.VehicleRepository import io.micronaut.context.ApplicationContext import io.micronaut.context.ApplicationContextProvider import io.micronaut.test.annotation.MicronautTest import spock.lang.AutoCleanup import spock.lang.Specification  import javax.inject.Inject  @MicronautTest class HelloDataSetsSpec extends Specification implements ApplicationContextProvider {      @AutoCleanup Dru dru = Dru.create(this)      @Inject ApplicationContext applicationContext     @Inject VehicleRepository vehicleRepository      void 'vehicles are loaded'() {         given:             dru.load(HelloDataSets.VEHICLES)         when:             Vehicle box = vehicleRepository.findByName('The Box')         then:             box             box.name == 'The Box'             box.make == 'Citroen'             box.model == 'Berlingo'     }  }<\/code><\/pre>\n<p>\u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u043e\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043d\u0430 Micronaut Data \u0432\u043c\u0435\u0441\u0442\u043e GORM. \u041d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0434\u0430\u043b\u0438\u043c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e GORM \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 GORM \u0438 Micronaut Data \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430, \u043d\u043e \u043d\u0435\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445. \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043d\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438. \u0422\u0430\u043a\u0436\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u0435 \u0441\u0442\u0430\u0440\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Grails, \u0435\u0441\u043b\u0438 \u0432\u044b \u0435\u0449\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438. \u0423\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u0435 \u0432\u0441\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0438\u043b\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u041f\u043e\u0432\u0442\u043e\u0440\u044f\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0439 \u0437\u0430\u043c\u0435\u043d\u044b \u0432\u0441\u0435\u0445 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0439.<\/p>\n<pre><code>.\/gradlew classes testClasses<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 <a href=\"https:\/\/github.com\/agorapulse\/goodbye-grails-hello-micronaut\/commit\/3ce205e5ff1116c569fd582ed4c338cdd2ebaf5c\"><u>\u0437\u0434\u0435\u0441\u044c<\/u><\/a>.<\/p>\n<p>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435? \u0412 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0431\u043e\u0440 \u0432\u0435\u0440\u0441\u0438\u0438 Micronaut \u0431\u044b\u043b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0432\u0432\u0438\u0434\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 Grails, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0437\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u043d\u0430 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Micronaut. \u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0441\u0442\u0430\u0442\u0435\u0439, \u043d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0435\u0442\u0435\u0441\u044c \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u043b\u044f Micronaut 1.x, \u0432\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f.<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/miro.medium.com\/max\/1200\/1*bF9mY4L6LcCCk-EjeybYVg.png&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>How to Resolve Conflicts in Micronaut 1.x and 2.x Library Versions in Gradle<\/span><\/div>\n<p><a href=\"https:\/\/medium.com\/agorapulse-stories\/how-to-resolve-conflicts-in-micronaut-1-x-and-2-x-library-versions-in-gradle-b0b5992ce4ce\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">medium.com<\/a><\/div>\n<\/div>\n<p>\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044b \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0439: <a href=\"https:\/\/medium.com\/agorapulse-stories\/goodbye-grails-hello-micronaut-7-services-f7d1ba4025f2\">\u0447\u0430\u0441\u0442\u044c 7<\/a>, <a href=\"https:\/\/medium.com\/agorapulse-stories\/goodbye-grails-hello-micronaut-8-controllers-724e51ec3925\">\u0447\u0430\u0441\u0442\u044c 8,<\/a> <a href=\"https:\/\/medium.com\/agorapulse-stories\/goodbye-grails-hello-micronaut-9-micronaut-application-c0d3956afe47\">\u0447\u0430\u0441\u0442\u044c 9<\/a>, <a href=\"https:\/\/medium.com\/agorapulse-stories\/goodbye-grails-hello-micronaut-10-micronaut-data-759c6c36bc7\">\u0447\u0430\u0441\u0442\u044c 10<\/a>.<\/p>\n<hr\/>\n<blockquote>\n<p>\u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 <a href=\"https:\/\/otus.pw\/wT5k\/\">\u043a\u0443\u0440\u0441\u0430 \u00abGroovy Developer\u00bb.<\/a> \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435, \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043f\u0440\u0435\u043f\u043e\u0434\u0430\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u043a\u0443\u0440\u0441\u0430 \u2014 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u043c \u043d\u0430 \u0434\u0435\u043d\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445 \u0434\u0432\u0435\u0440\u0435\u0439 \u043e\u043d\u043b\u0430\u0439\u043d. \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f <a href=\"https:\/\/otus.pw\/mMgL\/\"><strong>\u0437\u0434\u0435\u0441\u044c.<\/strong><\/a><\/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\/593989\/\"> https:\/\/habr.com\/ru\/articles\/593989\/<\/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<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0442\u0440\u0435\u0442\u044c\u044f \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0438\u0437 \u0446\u0438\u043a\u043b\u0430 \u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0437 Grails \u0432 Micronaut.\u00a0<em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435:<\/em>\u00a0\u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u0432 Grails 4.x \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438<em>.<\/em><\/p>\n<p>\u0412\u0441\u0435\u0433\u043e \u0432 \u0446\u0438\u043a\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0439 \u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0437 Grails \u0432 Micronaut 10 \u0447\u0430\u0441\u0442\u0435\u0439:<\/p>\n<p>\u041c\u043d\u043e\u0433\u043e\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442<br \/>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<br \/>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f<br \/>\u0414\u0430\u0442\u0430\u0441\u0435\u0442\u044b<br \/>\u041c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433<br \/>\u041a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438<br \/>\u0421\u0435\u0440\u0432\u0438\u0441\u044b<br \/>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<br \/>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Micronaut<br \/>Micronaut Data<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 Micronaut, Micronaut Data.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e (\u043e \u043c\u043d\u043e\u0433\u043e\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438) \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c\u00a0<a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/593895\/\"><strong>\u0437\u0434\u0435\u0441\u044c.<\/strong><\/a><\/p>\n<p>\u0412\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e (\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430\u0445, \u043c\u0430\u0440\u0448\u0430\u043b\u0438\u043d\u0433\u0435 \u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438) \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/593965\/\"><strong>\u0442\u0443\u0442.<\/strong> <\/a><\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<h2>\u0427\u0430\u0441\u0442\u044c 7. \u0421\u0435\u0440\u0432\u0438\u0441\u044b<\/h2>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043c\u044b \u0443\u0436\u0435 \u0438\u0437\u0432\u043b\u0435\u043a\u043b\u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u043f\u043e\u0434\u043f\u0440\u043e\u0435\u043a\u0442. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails. \u041d\u0435 \u0431\u0443\u0434\u0435\u043c \u043c\u0443\u0434\u0440\u0438\u0442\u044c \u0441 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0437\u043e\u0432\u0435\u043c \u044d\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>-core<\/code>.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043f\u0430\u043f\u043a\u0443 <code>hello-core<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>libs<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0435 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 <code>hello-core.gradle<\/code>.<\/p>\n<pre><code class=\"java\">dependencies {     api project(':hello-data')      annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor \"io.micronaut:micronaut-inject-java\"     annotationProcessor \"io.micronaut:micronaut-validation\"      implementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")      implementation \"io.micronaut:micronaut-core\"     implementation \"io.micronaut:micronaut-inject\"     implementation \"io.micronaut:micronaut-validation\"     implementation \"io.micronaut:micronaut-runtime\"      compileOnly \"io.micronaut:micronaut-inject-groovy\"      testImplementation project(\":hello-data-test-data\")      testImplementation(\"org.spockframework:spock-core\") {         exclude group: \"org.codehaus.groovy\", module: \"groovy-all\"     }      testImplementation \"io.micronaut:micronaut-inject-groovy\"     testImplementation \"io.micronaut.test:micronaut-test-spock\" }  tasks.withType(JavaExec) {     classpath += configurations.developmentOnly     jvmArgs('-noverify', '-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote') }  tasks.withType(JavaCompile){     options.encoding = \"UTF-8\"     options.compilerArgs.add('-parameters') }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0438\u0445 \u0432 \u0444\u0430\u0439\u043b <code>hello-core.gradle<\/code>.<\/p>\n<p>\u0418\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432<\/p>\n<ul>\n<li>\n<p><code>src\/main\/groovy<\/code><\/p>\n<\/li>\n<li>\n<p><code>grails-app\/services<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0432 \u043f\u0430\u043f\u043a\u0443 <code>src\/main\/groovy<\/code> \u043d\u043e\u0432\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<pre><code>implementation project(':hello-core')<\/code><\/pre>\n<p>\u0411\u0438\u043d\u044b Micronaut \u043b\u0443\u0447\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 Grails, \u0433\u0434\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f <code>FieldByName<\/code>.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 Grails:<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.VehicleDataService  @CompileStatic class VehicleService {      VehicleDataService vehicleDataService      \/\/ methods  }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043c\u044b \u0432\u043d\u0435\u0434\u0440\u044f\u0435\u043c \u043f\u043e \u0438\u043c\u0435\u043d\u0438 <code>VehicleDataService<\/code> \u0432 <code>VehicleService<\/code> \u0432 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>vehicleDataService<\/code>. \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0433\u0440\u0430\u0435\u0442 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0430\u0436\u043d\u0443\u044e \u0440\u043e\u043b\u044c \u0432 Grails.<\/p>\n<p>\u041c\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0438\u0437 <code>hello\/grails-app\/services<\/code> \u0432 <code>hello-core\/src\/main\/groovy<\/code>.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0435\u0433\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 \u0431\u0438\u043d Micronaut<\/p>\n<p>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0432 Micronaut \u0445\u043e\u0442\u044c \u0438 \u0434\u043b\u0438\u043d\u043d\u0435\u0435, \u0437\u0430\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>javax.inject.Singleton<\/code>, \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u043f\u043e\u043b\u044f \u043a\u0430\u043a private final \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0438\u0445 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435.<\/p>\n<p>\u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0438\u043c\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u043d\u043e\u0433\u043e \u0431\u0438\u043d\u0430 \u0443\u0436\u0435 \u043d\u0438 \u043d\u0430 \u0447\u0442\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442, \u0434\u0430 \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 Micronaut \u0431\u043e\u0433\u0430\u0447\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 Grails.<\/p>\n<p>\u0412\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 Grails. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043b\u0438\u0448\u044c \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@Inject<\/code> \u043f\u0435\u0440\u0435\u0434 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u043b\u044f.<\/p>\n<pre><code class=\"java\">class VehicleController {          @Inject VehicleService vehicleService          \/\/ controller actions  }<\/code><\/pre>\n<h3>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f Micronaut Grails<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 Grails \u0438\u0437 \u0431\u0438\u043d\u043e\u0432 Micronaut \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f GORM, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c Micronaut. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>GrailsApp<\/code> \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 Micronaut, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0430 \u0432\u044b\u0440\u0443\u0447\u043a\u0443 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/agorapulse.github.io\/micronaut-grails\/\"><u>Micronaut Grails<\/u><\/a>:<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Grails Integration for Micronaut<\/span><\/div>\n<p><a href=\"https:\/\/agorapulse.github.io\/micronaut-grails\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">agorapulse.github.io<\/a><\/div>\n<\/div>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u0434\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0444\u0430\u0439\u043b \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Grails\u00a0\u2014 <code>hello.gradle<\/code>:<\/p>\n<pre><code>implementation 'com.agorapulse:micronaut-grails:3.0.7' implementation 'com.agorapulse:micronaut-grails-web-boot:3.0.7'<\/code><\/pre>\n<p>\u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043d\u0443\u0436\u043d\u043e <strong>\u0443\u0434\u0430\u043b\u0438\u0442\u044c<\/strong> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code>compile \"org.grails:grails-web-boot\"<\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0441 <code>Application<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"java\">import com.agorapulse.micronaut.grails.MicronautGrailsApp import com.agorapulse.micronaut.grails.MicronautGrailsAutoConfiguration  import groovy.transform.CompileStatic import hello.legacy.Vehicle  @CompileStatic class Application extends MicronautGrailsAutoConfiguration {      final Collection&lt;Package> packages = [             Vehicle.package,     ]      static void main(String[] args) {         MicronautGrailsApp.run(Application, args)     }  }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 <code>MicronautGrailsAutoConfiguration<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>MicronautGrailsApp<\/code> \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0415\u0449\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0427\u0442\u043e\u0431\u044b \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0431\u0440\u0438\u043a\u0443, \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0449\u0443\u044e \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442\u044b.<\/p>\n<pre><code class=\"java\">import groovy.transform.CompileStatic import hello.legacy.VehicleDataService import io.micronaut.context.annotation.Bean import io.micronaut.context.annotation.Factory import spock.mock.DetachedMockFactory  import javax.inject.Singleton  @Factory @CompileStatic class MockDataServicesFactory {      @Bean     @Singleton     VehicleDataService vehicleDataService() {         return new DetachedMockFactory().Mock(VehicleDataService)     }  }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <code>Autowire<\/code> \u0432 Spring \u0438 <code>AutowiredTest<\/code> \u0432 Grail. \u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f <code>AutoAttach<\/code> \u0438\u0437 Spock \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u043a-\u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d \u043a \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"java\">import com.agorapulse.dru.Dru import com.agorapulse.gru.Gru import com.agorapulse.gru.grails.Grails import com.fasterxml.jackson.databind.ObjectMapper import grails.testing.gorm.DataTest import grails.testing.spring.AutowiredTest import grails.testing.web.controllers.ControllerUnitTest import hello.legacy.Vehicle import hello.legacy.VehicleDataService import org.springframework.beans.factory.annotation.Autowired import spock.lang.AutoCleanup import spock.lang.Specification import spock.mock.AutoAttach   class VehicleControllerSpec extends Specification implements ControllerUnitTest&lt;VehicleController>, DataTest, AutowiredTest{      @AutoCleanup Dru dru = Dru.create {         include HelloDataSets.VEHICLES     }      @AutoCleanup Gru gru = Gru.create(Grails.create(this)).prepare {         include UrlMappings     }      @Autowired @AutoAttach VehicleDataService vehicleDataService      @Override     Closure doWithSpring() {         return {             objectMapper(ObjectMapper)         }     }      void 'render with gru'() {         given:             dru.load()          when:              gru.test {                 get '\/vehicle\/1'                 expect {                     json 'vehicle.json'                 }             }          then:             gru.verify()              1 * vehicleDataService.findById(1) >> dru.findByType(Vehicle)     }  }<\/code><\/pre>\n<h4>\u041f\u043b\u0430\u0433\u0438\u043d\u044b Grails \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h4>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043c\u043d\u0438\u043c\u0443\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443 \u044d\u0442\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430, \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438. \u041e\u0431\u044b\u0447\u043d\u043e \u0432\u0430\u0448\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u044b Grails, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u044b\u0441\u043a\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438 \u0434\u043b\u044f Micronaut. \u0412 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Micronaut, Agorapulse OSS Hub \u0438\u043b\u0438 \u043a \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 Awesome Micronaut:<\/p>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/micronaut.io\/wp-content\/uploads\/2021\/02\/the-micronaut-framework.gif&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Docs &#8212; Micronaut Framework<\/span><\/div>\n<p><a href=\"https:\/\/micronaut.io\/docs\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">micronaut.io<\/a><\/div>\n<\/div>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;undefined&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>Agorapulse OSS Hub<\/span><\/div>\n<p><a href=\"https:\/\/agorapulse.github.io\/agorapulse-oss\/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">agorapulse.github.io<\/a><\/div>\n<\/div>\n<div class=\"embed_link\">\n<div class=\"embed__thumb\" style=\"background-image: url(&quot;https:\/\/opengraph.githubassets.com\/981498c4943f1529f8a1788c9cf8656326b813890b21a08e10e223b455d2da31\/JonasHavers\/awesome-micronaut&quot;);\"><\/div>\n<div class=\"embed__caption\">\n<div class=\"embed__caption-title\"><span>GitHub &#8212; JonasHavers\/awesome-micronaut: A curated list of resources for the Micronaut JVM framework<\/span><\/div>\n<p><a href=\"https:\/\/github.com\/JonasHavers\/awesome-micronaut\" target=\"_blank\" rel=\"noopener noreferrer nofollow\" class=\"embed__caption-link\">github.com<\/a><\/div>\n<\/div>\n<p>\u00a0<em>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433\u00a0\u2014 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432.<\/em><\/p>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 8. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<\/h2>\n<p>\u041d\u0430 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443. \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0435\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 Grails \u0432 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u043d\u0430 Micronaut.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 Grails.<\/p>\n<pre><code class=\"java\">import com.fasterxml.jackson.databind.ObjectMapper import groovy.transform.CompileStatic import hello.legacy.Vehicle import hello.legacy.VehicleDataService  import javax.inject.Inject  @CompileStatic class VehicleController {      @Inject ObjectMapper objectMapper     @Inject VehicleService vehicleService     @Inject VehicleDataService vehicleDataService      Object show(Long id) {         Vehicle vehicle = vehicleDataService.findById(id)         if (!vehicle) {             throw new NoSuchElementException(\"No vehicle found for id: $id\")         }         render contentType: 'application\/json', text: objectMapper.writeValueAsString(                 new VehicleResponse(                         id: vehicle.id,                         name: vehicle.name,                         make: vehicle.make,                         model: vehicle.model                 )         )     }      Object noSuchElement(NoSuchElementException e) {         render status: 404     }  }<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u0443\u0441\u043f\u0435\u0445\u043e\u043c.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 hello-api \u0432 \u043f\u0430\u043f\u043a\u0435 libs \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u0441\u0431\u043e\u0440\u043a\u0438, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 hello-api.gradle:<\/p>\n<pre><code class=\"java\"> dependencies {     api project(':hello-core')      annotationProcessor platform(\"io.micronaut:micronaut-bom:$micronautVersion\")     annotationProcessor \"io.micronaut:micronaut-inject-java\"     annotationProcessor \"io.micronaut:micronaut-validation\"      implementation platform(\"io.micronaut:micronaut-bom:$micronautVersion\")      implementation \"io.micronaut:micronaut-core\"     implementation \"io.micronaut:micronaut-inject\"     implementation \"io.micronaut:micronaut-validation\"     implementation \"io.micronaut:micronaut-runtime\"     implementation<\/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-401965","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/401965","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=401965"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/401965\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=401965"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=401965"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=401965"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}