{"id":293524,"date":"2019-08-18T15:01:05","date_gmt":"2019-08-18T15:01:05","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=293524"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=293524","title":{"rendered":"\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Spring"},"content":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<h3 id=\"predystoriya\">\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e HTTP API \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e RestTemplate \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u043e\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430. \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0431\u044b\u043b\u0430 \u0442\u0430\u043a\u043e\u0432\u0430\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">        if (headers == null) {             headers = new HttpHeaders();         }          if (headers.getFirst(&quot;Content-Type&quot;) == null) {             headers.add(&quot;Content-Type&quot;, MediaType.APPLICATION_JSON_VALUE);         }          HttpEntity&lt;Object&gt; entity;         if (body == null) {             entity = new HttpEntity&lt;&gt;(headers);         } else {             entity = new HttpEntity&lt;&gt;(body, headers);         }          final String uri = String.format(&quot;%s%s\/%s&quot;, workingUrl, apiPath, request.info());          final Class&lt;O&gt; type = (Class&lt;O&gt;) request.type();         final O response = (O)restTemplate.exchange(uri, request.method(), entity, type); <\/code><\/pre>\n<p>  <\/p>\n<p>\u2026 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0439 \u0442\u0438\u043f, \u0442\u0435\u043b\u043e \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0418 \u0432\u0441\u0435 \u0431\u044b \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u043a\u0430\u043a \u043a\u043e\u0441\u0442\u044b\u043b\u044c \u0438 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u044e\u0437\u0430\u0431\u0435\u043b\u044c\u043d\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Spring.<br \/>  \u0418 \u043f\u043e\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0438 \u0434\u0436\u0443\u043d\u044b \u043f\u0438\u0441\u0430\u043b\u0438 &quot;\u043a\u043e\u0441\u0442\u044b\u043b\u0438&quot; \u0432 \u0441\u0432\u043e\u0438\u0445 \u0432\u0435\u0442\u043a\u0430\u0445, \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u0430 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u0438\u0434\u0435\u044f \u2014 \u0430 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b &quot;\u0432 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u0447\u043a\u0443&quot; (like Feign).<\/p>\n<p>  <\/p>\n<h3 id=\"ideya\">\u0418\u0434\u0435\u044f<\/h3>\n<p>  <\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0432 \u0440\u0443\u043a\u0430\u0445 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043c\u043e\u0449\u043d\u044b\u0439 DI \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Spring, \u0442\u0430\u043a \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435? \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Data \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Jpa. \u041f\u0440\u0435\u0434\u043e \u043c\u043d\u043e\u0439 \u0441\u0442\u043e\u044f\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430 \u0442\u0438\u043f\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Spring \u0438 \u0442\u0440\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u0430\u043a \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u2014 Aspect, PostProcess \u0438 BeanDefinitionRegistrar.<\/p>\n<p>  <\/p>\n<h3 id=\"kodovaya-baza\">\u041a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430<\/h3>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438, \u043a\u0443\u0434\u0430 \u0436\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445, \u0438\u043d\u0430\u0447\u0435 \u043a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<p>  <\/p>\n<p>1) Mapping \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f, \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a\u0430\u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 HTTP \u0432\u044b\u0437\u043e\u0432\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Mapping {     \/**      * Registered service application name, need for config      *\/     String alias(); }<\/code><\/pre>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 alias \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0431\u0443\u0434\u044c \u0442\u043e <a href=\"https:\/\/habr.com\">https:\/\/habr.com<\/a>, <a href=\"https:\/\/github.com\">https:\/\/github.com<\/a>, etc.<\/p>\n<p>  <\/p>\n<p>2) ServiceMapping \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f, \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043c\u0435\u0442\u043e\u0434 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432\u044b\u0437\u0432\u0430\u043d \u043a\u0430\u043a \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 HTTP \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e, \u043e\u0442\u043a\u0443\u0434\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043b\u0438\u0431\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface ServiceMapping {     \/**      * Registered service application route      *\/     String path();      \/**      * Registered service application route http-method      *\/     HttpMethod method();      Header[] defaultHeaders() default {};      Class&lt;?&gt; fallbackClass() default Object.class;      String fallbackMethod() default &quot;&quot;; }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/strong><\/p>\n<p>  <\/p>\n<ul>\n<li><strong>path<\/strong> \u2014 \u043f\u0443\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0440\u0438\u043c\u0435\u0440 alias + \/ru\/hub\/${hub_name};<\/li>\n<li><strong>method<\/strong> \u2014 \u043c\u0435\u0442\u043e\u0434 HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (GET, POST, PUT, etc.);<\/li>\n<li><strong>defaultHeaders<\/strong> \u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0435 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (Content-Type, Accept, etc.);<\/li>\n<li><strong>fallbackClass<\/strong> \u2014 \u043a\u043b\u0430\u0441\u0441 \u043e\u0442\u0431\u0440\u0430\u043a\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 (Exception);<\/li>\n<li><strong>fallbackMethod<\/strong> \u2014 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u043a\u043b\u0430\u0441\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 (Exception).<\/li>\n<\/ul>\n<p>  <\/p>\n<p>3) Header \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f, \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 <\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) @Documented public @interface Header {     String name();      String value(); }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/strong><\/p>\n<p>  <\/p>\n<ul>\n<li><strong>name<\/strong> \u2014 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430;<\/li>\n<li><strong>value<\/strong> \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u0430\u043f \u2014 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0432\u043e\u0435\u0433\u043e FactoryBean \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">MappingFactoryBean.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package org.restclient.factory;  import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.restclient.annotations.RestInterceptor; import org.restclient.annotations.ServiceMapping; import org.restclient.annotations.Type; import org.restclient.config.ServicesConfiguration; import org.restclient.config.ServicesConfiguration.RouteSettings; import org.restclient.interceptor.Interceptor; import org.restclient.model.MappingMetadata; import org.restclient.model.Pair; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.jmx.access.InvocationFailureException; import org.springframework.lang.NonNull; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.client.RestClientResponseException; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient.ResponseSpec; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono;  import javax.naming.ConfigurationException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.*;  \/**  * @author: GenCloud  * @created: 2019\/08  *\/ @Slf4j @ToString public class MappingFactoryBean implements BeanFactoryAware, FactoryBean&lt;Object&gt;, ApplicationContextAware {     private static final Collection&lt;String&gt; ignoredMethods = Arrays.asList(&quot;equals&quot;, &quot;hashCode&quot;, &quot;toString&quot;);      private Class&lt;?&gt; type;     private List&lt;Object&gt; fallbackInstances;     private List&lt;MappingMetadata&gt; metadatas;     private String alias;     private ApplicationContext applicationContext;     private BeanFactory beanFactory;      @Override     public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {         this.applicationContext = applicationContext;     }      @Override     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {         this.beanFactory = beanFactory;     }      @Override     public Class&lt;?&gt; getObjectType() {         return type;     }      @Override     public boolean isSingleton() {         return true;     }      @Override     public Object getObject() {         return Enhancer.create(type, (MethodInterceptor) (instance, method, args, methodProxy) -&gt; {             final boolean skip = ignoredMethods.stream().anyMatch(ignore -&gt; method.getName().equals(ignore));              final ServiceMapping annotation = method.getAnnotation(ServiceMapping.class);             if (!skip &amp;&amp; annotation != null) {                 return invokeMethod(annotation, method, args);             }             return null;         });     }      \/**      * It determines the meta-information of the executing method, calling an HTTP request based on the      * meta-information found; interceptors are also called.      *      * @param annotation - main annotation that defines the path, type, standard request parameters.      * @param method     - callable method      * @param args       - method arguments      * @return if the request is executed without errors, returns a clean server response in wrappers Mono\/Flux.      * @throws Throwable      *\/     private Object invokeMethod(ServiceMapping annotation, Method method, Object[] args) throws Throwable {         final MappingMetadata metadata = findMetadataByMethodName(method.getName());         if (metadata == null) {             throw new NoSuchMethodException(String.format(&quot;Cant find metadata for method %s. Check your mapping configuration!&quot;, method.getName()));         }          final RouteSettings routeSettings = findSettingsByAlias(alias);         final String host = routeSettings.getHost();          String url = metadata.getUrl().replace(String.format(&quot;${%s}&quot;, alias), host);          final HttpMethod httpMethod = metadata.getHttpMethod();         final HttpHeaders httpHeaders = metadata.getHttpHeaders();          final List&lt;Pair&lt;String, Object&gt;&gt; foundVars = new ArrayList&lt;&gt;();         final List&lt;Pair&lt;String, Object&gt;&gt; foundParams = new ArrayList&lt;&gt;();         final List&lt;Pair&lt;String, Object&gt;&gt; foundHeaders = new ArrayList&lt;&gt;();          final Parameter[] parameters = method.getParameters();          final Object body = initHttpVariables(args, parameters, foundVars, foundParams, foundHeaders);          url = replaceHttpVariables(url, foundVars, foundParams, foundHeaders, httpHeaders);          preHandle(args, body, httpHeaders);          if (log.isDebugEnabled()) {             log.debug(&quot;Execute Service Mapping request&quot;);             log.debug(&quot;Url: {}&quot;, url);             log.debug(&quot;Headers: {}&quot;, httpHeaders);             if (body != null) {                 log.debug(&quot;Body: {}&quot;, body);             }         }          final Object call = handleHttpCall(annotation, args, url, httpMethod, body, httpHeaders, metadata);         postHandle(ResponseEntity.ok(call));         return call;     }      private Object handleHttpCall(ServiceMapping annotation, Object[] args, String url, HttpMethod httpMethod, Object body, HttpHeaders httpHeaders, MappingMetadata metadata) throws Throwable {         final WebClient webClient = WebClient.create(url);          ResponseSpec responseSpec;         final Class&lt;?&gt; returnType = metadata.getReturnType();         try {             if (body != null) {                 responseSpec = webClient                         .method(httpMethod)                         .headers(c -&gt; c.addAll(httpHeaders))                         .body(BodyInserters.fromPublisher(Mono.just(body), Object.class))                         .retrieve();             } else {                 responseSpec = webClient                         .method(httpMethod)                         .headers(c -&gt; c.addAll(httpHeaders))                         .retrieve();             }         } catch (RestClientResponseException ex) {             if (log.isDebugEnabled()) {                 log.debug(&quot;Error on execute route request - Code: {}, Error: {}, Route: {}&quot;, ex.getRawStatusCode(), ex.getResponseBodyAsString(), url);             }              final String fallbackMethod = metadata.getFallbackMethod();              final Object target = fallbackInstances.stream()                     .filter(o -&gt;                             o.getClass().getSimpleName().equals(annotation.fallbackClass().getSimpleName()))                     .findFirst().orElse(null);              Method fallback = null;             if (target != null) {                 fallback = Arrays.stream(target.getClass().getMethods())                         .filter(m -&gt; m.getName().equals(fallbackMethod))                         .findFirst()                         .orElse(null);             }              if (fallback != null) {                 args = Arrays.copyOf(args, args.length + 1);                 args[args.length - 1] = ex;                 final Object result = fallback.invoke(target, args);                 return Mono.just(result);             } else if (returnType == Mono.class) {                 return Mono.just(ResponseEntity.status(ex.getRawStatusCode()).body(ex.getResponseBodyAsString()));             } else if (returnType == Flux.class) {                 return Flux.just(ResponseEntity.status(ex.getRawStatusCode()).body(ex.getResponseBodyAsString()));             } else {                 return Mono.empty();             }         }          final Method method = metadata.getMethod();         final Type classType = method.getDeclaredAnnotation(Type.class);         final Class&lt;?&gt; type = classType == null ? Object.class : classType.type();          if (returnType == Mono.class) {             return responseSpec.bodyToMono(type);         } else if (returnType == Flux.class) {             return responseSpec.bodyToFlux(type);         }          return null;     }      private String replaceHttpVariables(String url, final List&lt;Pair&lt;String, Object&gt;&gt; foundVars, final List&lt;Pair&lt;String, Object&gt;&gt; foundParams,                                         final List&lt;Pair&lt;String, Object&gt;&gt; foundHeaders, final HttpHeaders httpHeaders) {         for (Pair&lt;String, Object&gt; pair : foundVars) {             url = url.replace(String.format(&quot;${%s}&quot;, pair.getKey()), String.valueOf(pair.getValue()));         }          for (Pair&lt;String, Object&gt; pair : foundParams) {             url = url.replace(String.format(&quot;${%s}&quot;, pair.getKey()), String.valueOf(pair.getValue()));         }          foundHeaders.forEach(pair -&gt; {             final String headerName = pair.getKey();             if (httpHeaders.getFirst(headerName) != null) {                 httpHeaders.set(headerName, String.valueOf(pair.getValue()));             } else {                 log.warn(&quot;Undefined request header name '{}'! Check mapping configuration!&quot;, headerName);             }         });          return url;     }      private Object initHttpVariables(final Object[] args, final Parameter[] parameters, final List&lt;Pair&lt;String, Object&gt;&gt; foundVars,                                      final List&lt;Pair&lt;String, Object&gt;&gt; foundParams, final List&lt;Pair&lt;String, Object&gt;&gt; foundHeaders) {         Object body = null;         for (int i = 0; i &lt; parameters.length; i++) {             final Object value = args[i];             final Parameter parameter = parameters[i];              final PathVariable pv = parameter.getDeclaredAnnotation(PathVariable.class);             final RequestParam rp = parameter.getDeclaredAnnotation(RequestParam.class);             final RequestHeader rh = parameter.getDeclaredAnnotation(RequestHeader.class);             final RequestBody rb = parameter.getDeclaredAnnotation(RequestBody.class);              if (rb != null) {                 body = value;             }              if (rh != null) {                 foundHeaders.add(new Pair&lt;&gt;(rh.value(), value));             }              if (pv != null) {                 final String name = pv.value();                 foundVars.add(new Pair&lt;&gt;(name, value));             }              if (rp != null) {                 final String name = rp.value();                 foundParams.add(new Pair&lt;&gt;(name, value));             }         }          return body;     }      private void preHandle(Object[] args, Object body, HttpHeaders httpHeaders) {         final Map&lt;String, Interceptor&gt; beansOfType = applicationContext.getBeansOfType(Interceptor.class);         beansOfType.values()                 .stream()                 .filter(i -&gt;                         i.getClass().isAnnotationPresent(RestInterceptor.class)                                 &amp;&amp; ArrayUtils.contains(i.getClass().getDeclaredAnnotation(RestInterceptor.class).aliases(), alias))                 .forEach(i -&gt; i.preHandle(args, body, httpHeaders));     }      private void postHandle(ResponseEntity&lt;?&gt; responseEntity) {         final Map&lt;String, Interceptor&gt; beansOfType = applicationContext.getBeansOfType(Interceptor.class);         beansOfType.values()                 .stream()                 .filter(i -&gt;                         i.getClass().isAnnotationPresent(RestInterceptor.class)                                 &amp;&amp; ArrayUtils.contains(i.getClass().getDeclaredAnnotation(RestInterceptor.class).aliases(), alias))                 .forEach(i -&gt; i.postHandle(responseEntity));     }      private MappingMetadata findMetadataByMethodName(String methodName) {         return metadatas                 .stream()                 .filter(m -&gt; m.getMethodName().equals(methodName)).findFirst()                 .orElseThrow(() -&gt; new InvocationFailureException(&quot;&quot;));     }      private RouteSettings findSettingsByAlias(String alias) throws ConfigurationException {         final ServicesConfiguration servicesConfiguration = applicationContext.getAutowireCapableBeanFactory().getBean(ServicesConfiguration.class);         return servicesConfiguration.getRoutes()                 .stream()                 .filter(r -&gt;                         r.getAlias().equals(alias))                 .findFirst()                 .orElseThrow(() -&gt; new ConfigurationException(String.format(&quot;Cant find service host! Check configuration. Alias: %s&quot;, alias)));     }      @SuppressWarnings(&quot;unused&quot;)     public Class&lt;?&gt; getType() {         return type;     }      @SuppressWarnings(&quot;unused&quot;)     public void setType(Class&lt;?&gt; type) {         this.type = type;     }      @SuppressWarnings(&quot;unused&quot;)     public List&lt;MappingMetadata&gt; getMetadatas() {         return metadatas;     }      @SuppressWarnings(&quot;unused&quot;)     public void setMetadatas(List&lt;MappingMetadata&gt; metadatas) {         this.metadatas = metadatas;     }      @SuppressWarnings(&quot;unused&quot;)     public String getAlias() {         return alias;     }      @SuppressWarnings(&quot;unused&quot;)     public void setAlias(String alias) {         this.alias = alias;     }      @SuppressWarnings(&quot;unused&quot;)     public List&lt;Object&gt; getFallbackInstances() {         return fallbackInstances;     }      @SuppressWarnings(&quot;unused&quot;)     public void setFallbackInstances(List&lt;Object&gt; fallbackInstances) {         this.fallbackInstances = fallbackInstances;     }      @Override     public boolean equals(Object o) {         if (this == o) return true;         if (o == null || getClass() != o.getClass()) return false;         MappingFactoryBean that = (MappingFactoryBean) o;         return Objects.equals(type, that.type);     }      @Override     public int hashCode() {         return Objects.hash(type);     } }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044e, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0431\u0438\u043d\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u0430-\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0443, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0441\u0430\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f\u043c\u0438, \u043a\u043b\u0430\u0441\u0441\u044b \u043e\u0442\u0431\u0440\u0430\u043a\u043e\u0432\u043a\u0438, \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430;<\/li>\n<li>\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e CGlib (MappingFactoryBean#getObject()), \u0442.\u0435. \u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0435\u0442, \u043d\u043e \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043c\u0435\u0442\u043e\u0434\u0430 \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0440\u0435\u0442\u044c\u0438\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 DI \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Spring, \u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 ImportBeanDefinitionRegistrar.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ServiceMappingRegistrator.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">package org.restclient.factory;  import lombok.extern.slf4j.Slf4j; import org.restclient.annotations.Header; import org.restclient.annotations.Mapping; import org.restclient.annotations.ServiceMapping; import org.restclient.model.MappingMetadata; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.lang.NonNull; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam;  import javax.naming.ConfigurationException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.*; import java.util.stream.Collectors;  \/**  * @author: GenCloud  * @created: 2019\/08  *\/ @Slf4j public class ServiceMappingRegistrator implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {     private ResourceLoader resourceLoader;     private Environment environment;      @Override     public void setEnvironment(@NonNull Environment environment) {         this.environment = environment;     }      @Override     public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {         this.resourceLoader = resourceLoader;     }      @Override     public void registerBeanDefinitions(@NonNull AnnotationMetadata metadata, @NonNull BeanDefinitionRegistry registry) {         registerMappings(metadata, registry);     }      private void registerMappings(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {         final ClassPathScanningCandidateComponentProvider scanner = getScanner();         scanner.setResourceLoader(resourceLoader);          final Set&lt;String&gt; basePackages = getBasePackages(metadata);          final AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(Mapping.class);         scanner.addIncludeFilter(annotationTypeFilter);          basePackages                 .stream()                 .map(scanner::findCandidateComponents)                 .flatMap(Collection::stream)                 .filter(candidateComponent -&gt; candidateComponent instanceof AnnotatedBeanDefinition)                 .map(candidateComponent -&gt; (AnnotatedBeanDefinition) candidateComponent)                 .map(AnnotatedBeanDefinition::getMetadata)                 .map(ClassMetadata::getClassName)                 .forEach(className -&gt; buildGateway(className, registry));     }      private void buildGateway(String className, BeanDefinitionRegistry registry) {         try {             final Class&lt;?&gt; type = Class.forName(className);             final List&lt;Method&gt; methods = Arrays                     .stream(type.getMethods())                     .filter(method -&gt;                             method.isAnnotationPresent(ServiceMapping.class))                     .collect(Collectors.toList());              final String alias = type.getDeclaredAnnotation(Mapping.class).alias();              final List&lt;MappingMetadata&gt; metadatas = new ArrayList&lt;&gt;();              final List&lt;Object&gt; fallbackInstances = new ArrayList&lt;&gt;();              for (Method method : methods) {                 final ServiceMapping serviceMapping = method.getDeclaredAnnotation(ServiceMapping.class);                  final Class&lt;?&gt;[] args = method.getParameterTypes();                  final Header[] defaultHeaders = serviceMapping.defaultHeaders();                  final String path = serviceMapping.path();                 final HttpMethod httpMethod = serviceMapping.method();                 final HttpHeaders httpHeaders = new HttpHeaders();                  final StringBuilder url = new StringBuilder();                 url.append(&quot;${&quot;).append(alias).append(&quot;}&quot;).append(path);                  final Parameter[] parameters = method.getParameters();                 for (int i = 0; i &lt; parameters.length; i++) {                     final Parameter parameter = parameters[i];                     for (Annotation annotation : parameter.getAnnotations()) {                         if (!checkValidParams(annotation, args)) {                             break;                         }                          if (annotation instanceof RequestParam) {                             final String argName = ((RequestParam) annotation).value();                             if (argName.isEmpty()) {                                 throw new ConfigurationException(&quot;Configuration error: defined RequestParam annotation dont have value! Api method: &quot; + method.getName() + &quot;, Api Class: &quot; + type);                             }                              final String toString = url.toString();                             if (toString.endsWith(&quot;&amp;&quot;) &amp;&amp; i + 1 == args.length) {                                 url.append(argName).append(&quot;=&quot;).append(&quot;${&quot;).append(argName).append(&quot;}&quot;);                             } else if (!toString.endsWith(&quot;&amp;&quot;) &amp;&amp; i + 1 == args.length) {                                 url.append(&quot;?&quot;).append(argName).append(&quot;=&quot;).append(&quot;${&quot;).append(argName).append(&quot;}&quot;);                             } else if (!toString.endsWith(&quot;&amp;&quot;)) {                                 url.append(&quot;?&quot;).append(argName).append(&quot;=&quot;).append(&quot;${&quot;).append(argName).append(&quot;}&quot;).append(&quot;&amp;&quot;);                             } else {                                 url.append(argName).append(&quot;=&quot;).append(&quot;${&quot;).append(argName).append(&quot;}&quot;).append(&quot;&amp;&quot;);                             }                         } else if (annotation instanceof PathVariable) {                             final String argName = ((PathVariable) annotation).value();                             if (argName.isEmpty()) {                                 throw new ConfigurationException(&quot;Configuration error: defined PathVariable annotation dont have value! Api method: &quot; + method.getName() + &quot;, Api Class: &quot; + type);                             }                              final String toString = url.toString();                             final String argStr = String.format(&quot;${%s}&quot;, argName);                             if (!toString.contains(argStr)) {                                 if (toString.endsWith(&quot;\/&quot;)) {                                     url.append(argStr);                                 } else {                                     url.append(&quot;\/&quot;).append(argStr);                                 }                             }                         } else if (annotation instanceof RequestHeader) {                             final String argName = ((RequestHeader) annotation).value();                             if (argName.isEmpty()) {                                 throw new ConfigurationException(&quot;Configuration error: defined RequestHeader annotation dont have value! Api method: &quot; + method.getName() + &quot;, Api Class: &quot; + type);                             }                              httpHeaders.add(argName, String.format(&quot;${%s}&quot;, argName));                         }                     }                 }                  if (defaultHeaders.length &gt; 0) {                     Arrays.stream(defaultHeaders)                             .forEach(header -&gt; httpHeaders.add(header.name(), header.value()));                 }                  final Object instance = serviceMapping.fallbackClass().newInstance();                 fallbackInstances.add(instance);                  final String fallbackName = serviceMapping.fallbackMethod();                 final String buildedUrl = url.toString();                 final MappingMetadata mappingMetadata = new MappingMetadata(method, httpMethod, buildedUrl, httpHeaders, fallbackName);                 metadatas.add(mappingMetadata);                  log.info(&quot;Bind api path - alias: {}, url: {}&quot;, alias, buildedUrl);             }              final BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingFactoryBean.class);             beanDefinitionBuilder.addPropertyValue(&quot;type&quot;, className);             beanDefinitionBuilder.addPropertyValue(&quot;alias&quot;, alias);             beanDefinitionBuilder.addPropertyValue(&quot;metadatas&quot;, metadatas);             beanDefinitionBuilder.addPropertyValue(&quot;fallbackInstances&quot;, fallbackInstances);              final AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();              final BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{type.getSimpleName()});             BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);         } catch (IllegalAccessException | InstantiationException | ClassNotFoundException | ConfigurationException e) {             e.printStackTrace();         }     }      private boolean checkValidParams(Annotation annotation, Object[] args) {         Arrays                 .stream(args)                 .map(Object::getClass)                 .forEach(type -&gt; {                     if (annotation instanceof RequestParam) {                         if (type.isAnnotationPresent(PathVariable.class)) {                             throw new IllegalArgumentException(&quot;Annotation RequestParam cannot be used with PathVariable&quot;);                         }                     } else if (annotation instanceof PathVariable) {                         if (type.isAnnotationPresent(RequestParam.class)) {                             throw new IllegalArgumentException(&quot;Annotation PathVariable cannot be used with RequestParam&quot;);                         }                     }                 });          return true;     }      private Set&lt;String&gt; getBasePackages(AnnotationMetadata importingClassMetadata) {         Map&lt;String, Object&gt; attributes = importingClassMetadata.getAnnotationAttributes(SpringBootApplication.class.getCanonicalName());         if (attributes == null) {             attributes = importingClassMetadata.getAnnotationAttributes(ComponentScan.class.getCanonicalName());         }          Set&lt;String&gt; basePackages = new HashSet&lt;&gt;();         if (attributes != null) {             basePackages = Arrays.stream((String[]) attributes.get(&quot;scanBasePackages&quot;)).filter(StringUtils::hasText).collect(Collectors.toSet());              Arrays.stream((Class[]) attributes.get(&quot;scanBasePackageClasses&quot;)).map(ClassUtils::getPackageName).forEach(basePackages::add);         }          if (basePackages.isEmpty()) {             basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));         }          return basePackages;     }      private ClassPathScanningCandidateComponentProvider getScanner() {         return new ClassPathScanningCandidateComponentProvider(false, environment) {             @Override             protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {                 boolean isCandidate = false;                 if (beanDefinition.getMetadata().isIndependent()) {                     if (!beanDefinition.getMetadata().isAnnotation()) {                         isCandidate = true;                     }                 }                 return isCandidate;             }         };     } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0422.\u0435. \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0440\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u043a\u043e\u0433\u0434\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 Spring REFRESH, \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 ImportBeanDefinitionRegistrar, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 registerBeanDefinitions \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0430\u043d\u043d\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u0438 \u0444\u0430\u0431\u0440\u0438\u043a\u0430-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\/\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0431\u0438\u043d\u043e\u0432 (\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432, etc.), \u0438 \u043f\u0440\u044f\u043c\u043e \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 &quot;\u0432 \u043a\u0430\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043a\u043e\u043f\u0430\u0442\u044c&quot; \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u043d\u0430\u0448\u0438\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u0438 \u0438\u0445 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e BeanDefinitionBulder \u0438 \u043d\u0430\u0448\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 MappingFactoryBean. \u0414\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <a href=\"https:\/\/habr.com\/ru\/users\/import\/\" class=\"user_link\">Import<\/a> \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 (\u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0443\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 RestClientAutoConfiguration, \u0433\u0434\u0435 \u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u043e\u0434\u0443\u043b\u044f).<\/p>\n<p>  <\/p>\n<h3 id=\"kak-ispolzovat\">\u041a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/h3>\n<p>  <\/p>\n<p>\u041a\u0435\u0439\u0441 \u2014 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0435\u043a\u043e\u0435\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f GitHub \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>  <\/p>\n<p>1) \u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c (application.yml)<\/p>\n<p>  <\/p>\n<pre><code class=\"xml\">services:   routes:     - host: https:\/\/api.github.com # \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0410\u041f\u0418 GitHub       alias: github-service # \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0435\u0435\u0441\u044f \u0432 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 Mapping<\/code><\/pre>\n<p>  <\/p>\n<p>1) \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@Mapping(alias = &quot;github-service&quot;) \/\/ \u0430\u043b\u0438\u0430\u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 public interface RestGateway {     \/**      * \u041c\u0435\u0442\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.      *      * @param userName - \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c GitHub      * @return \u043c\u0430\u0441\u0441\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 LinkedHashMap      *\/     @ServiceMapping(path = &quot;\/users\/${userName}\/repos&quot;, method = GET)     @Type(type = ArrayList.class) \/\/ \u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043e\u0431\u0435\u0440\u0442\u043a\u0435 Mono\/Flux     Mono&lt;ArrayList&gt; getRepos(@PathVariable(&quot;userName&quot;) String userName); }<\/code><\/pre>\n<p>  <\/p>\n<p>2) \u0412\u044b\u0437\u043e\u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@SprinBootApplication public class RestApp {     public static void main(String... args) {         final ConfigurableApplicationContext context = SpringApplication.run(RestApp.class, args);         final RestGateway restGateway = context.getType(RestGateway.class);         final Mono&lt;ArrayList&gt; response = restGateway.getRepos(&quot;gencloud&quot;);         response.doOnSuccess(list -&gt;                  log.info(&quot;Received response: {}&quot;, list)).subscribe();     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432 \u0434\u0435\u0431\u0430\u0433\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u044d\u0442\u043e (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043b\u043e\u0436\u0438\u0442\u044c \u0437\u0430 \u043c\u0435\u0441\u0442\u043e \u0442\u0438\u043f\u0430 ArrayList \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u0443\u044e \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e json \u043e\u0442\u0432\u0435\u0442\u0430; \u043a\u043e\u0434 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u044e\u043d\u0438\u0442 \u0442\u0435\u0441\u0442 \u0432 \u043a\u0443\u043f\u0435 \u0441 reactor-test \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439, \u043d\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f):<br \/>  <img decoding=\"async\" src=\"http:\/\/i.piccy.info\/i9\/2501ef36d89ade75cfe1960c05f51193\/1566129929\/42763\/1333383\/Screenshot_6.png\" alt=\"image\"\/><\/p>\n<p>  <\/p>\n<h3 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u041d\u0435 \u0432\u0441\u0435\u043c \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043f\u043e \u0434\u0443\u0448\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0434\u0435\u0431\u0430\u0433, \u043d\u0435 \u0442\u0430\u043c \u0442\u043a\u043d\u0443\u043b \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043e\u043f\u043b\u0435\u0443\u0445\u0443 \u043e\u0442 ConfigurationException, \u0435\u0449\u0435 \u0438 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0438 \u043f\u0438\u0441\u0430\u0442\u044c, \u043e\u0439\u2026<br \/>  \u041f\u0440\u0438\u043c\u0443 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044e API, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u044b\u043b\u0430 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<p>  <\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u2014 <a href=\"https:\/\/github.com\/GenCloud\/rest_client\">https:\/\/github.com\/GenCloud\/rest_client<\/a>.<\/p>\n<\/div>\n<p>               <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d()}}}t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>     <br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/464089\/\"> https:\/\/habr.com\/ru\/post\/464089\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<h3 id=\"predystoriya\">\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e HTTP API \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e RestTemplate \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u043e\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430. \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0431\u044b\u043b\u0430 \u0442\u0430\u043a\u043e\u0432\u0430\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">        if (headers == null) {             headers = new HttpHeaders();         }          if (headers.getFirst(&quot;Content-Type&quot;) == null) {             headers.add(&quot;Content-Type&quot;, MediaType.APPLICATION_JSON_VALUE);         }          HttpEntity&lt;Object&gt; entity;         if (body == null) {             entity = new HttpEntity&lt;&gt;(headers);         } else {             entity = new HttpEntity&lt;&gt;(body, headers);         }          final String uri = String.format(&quot;%s%s\/%s&quot;, workingUrl, apiPath, request.info());          final Class&lt;O&gt; type = (Class&lt;O&gt;) request.type();         final O response = (O)restTemplate.exchange(uri, request.method(), entity, type); <\/code><\/pre>\n<p>  <\/p>\n<p>\u2026 \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u0439 \u0442\u0438\u043f, \u0442\u0435\u043b\u043e \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0418 \u0432\u0441\u0435 \u0431\u044b \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u043a\u0430\u043a \u043a\u043e\u0441\u0442\u044b\u043b\u044c \u0438 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u044e\u0437\u0430\u0431\u0435\u043b\u044c\u043d\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Spring.<br \/>  \u0418 \u043f\u043e\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0438 \u0434\u0436\u0443\u043d\u044b \u043f\u0438\u0441\u0430\u043b\u0438 &quot;\u043a\u043e\u0441\u0442\u044b\u043b\u0438&quot; \u0432 \u0441\u0432\u043e\u0438\u0445 \u0432\u0435\u0442\u043a\u0430\u0445, \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u0430 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u0438\u0434\u0435\u044f \u2014 \u0430 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b &quot;\u0432 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u0447\u043a\u0443&quot; (like Feign).<\/p>\n<p>  <\/p>\n<h3 id=\"ideya\">\u0418\u0434\u0435\u044f<\/h3>\n<p>  <\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0432 \u0440\u0443\u043a\u0430\u0445 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043c\u043e\u0449\u043d\u044b\u0439 DI \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Spring, \u0442\u0430\u043a \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435? \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Data \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Jpa. \u041f\u0440\u0435\u0434\u043e \u043c\u043d\u043e\u0439 \u0441\u0442\u043e\u044f\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430 \u0442\u0438\u043f\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Spring \u0438 \u0442\u0440\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u0430\u043a \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u2014 Aspect, PostProcess \u0438 BeanDefinitionRegistrar.<\/p>\n<p>  <\/p>\n<h3 id=\"kodovaya-baza\">\u041a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430<\/h3>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438, \u043a\u0443\u0434\u0430 \u0436\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445, \u0438\u043d\u0430\u0447\u0435 \u043a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<p>  <\/p>\n<p>1) Mapping \u2014 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f, \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a\u0430\u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 HTTP \u0432\u044b\u0437\u043e\u0432\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"java\">@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Mapping {     \/**      * Registered service application name, need for config      *\/     String alias(); }<\/code><\/pre>\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-293524","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/293524","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=293524"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/293524\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=293524"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=293524"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=293524"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}