springCloud 의 RestTemplate + @ LoadBalanced 주석 부하 균형 소스 분석 실현
31167 단어 spring
첫 번 째 단계: 소스 코드 를 보기 전에 우 리 는 먼저 소비자 마이크로 서 비 스 를 구축 합 니 다. (여기 서 주로 springCloud 의 Ribbon 부하 균형 을 설명 하기 때문에 등록 센터 와 공급 자 는 더 이상 설명 하지 않 습 니 다)
1. 필요 한 maven 의존 도입:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.9.RELEASEversion>
<relativePath />
parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Edgware.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-ribbonartifactId>
dependency>
dependencies>
2. springboot 의 시작 클래스 를 만 듭 니 다:
@SpringBootApplication
@EnableDiscoveryClient
public class HelloApplicaton {
// RestTemplate Bean
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(HelloApplicaton.class, args);
}
}
3. resource 에서 시작 파일 설정: application. yml 또는 application. properties (구체 적 인 프로필 의 역할 은 제 가 설명 하지 않 아 도 될 것 같 습 니 다)
server:
port: 9091
spring:
application:
name: post-service
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
4. 소비자 요청 인터페이스 만 들 기:
@RestController
public class HelloController {
// RestTemplate
@Autowired
public RestTemplate restTemplate;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String postHello(){
// RestTemplate
return restTemplate.getForEntity("http://HELLO-SERVICE/hello"
,String.class,"").getBody();
}
}
주: 이곳 의 HELLO - SERVICE 는 등록 센터 에 존재 하 는 마이크로 서비스의 이름 입 니 다. 이것 은 모두 가 잘 알 고 있 을 것 입 니 다.
이렇게 부하 균형 능력 을 가 진 소비자 인 터 페 이 스 를 만 드 는 데 성공 했다!
그런데 왜 @ LoadBalanced 주해 로 수 정 된 RestTemplate 에 부하 균형 능력 이 생 겼 는 지 먼저 @ LoadBalanced 주 해 를 보십시오.
/**
* Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
* @author Spencer Gibb
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
이것 은 일반적인 태그 주석 입 니 다. RestTemplate 를 수식 하여 부하 균형 능력 을 가지 게 하 는 역할 을 합 니 다. org. springframework. cloud. client. loadbancer 패키지 아래 의 class 를 보면 LoadBalancer AutoConfiguration 과 같은 종 류 를 쉽게 발견 할 수 있 습 니 다.
@Configuration// @ConditionalOnClass(RestTemplate.class)// RestTemplate LoadBalancerClient //Bean @ConditionalOnBean(LoadBalancerClient.class) @EnableConfigurationProperties(LoadBalancerRetryProperties.class) public class LoadBalancerAutoConfiguration {
// , restTemplates @LoadBalanced , (Autowired ) @LoadBalanced @Autowired(required = false) private List
restTemplates = Collections.emptyList(); @Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializer( final List customizers) { return new SmartInitializingSingleton() { @Override public void afterSingletonsInstantiated() { for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) { for (RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); } } } }; } @Autowired(required = false) private List transformers = Collections.emptyList(); @Bean @ConditionalOnMissingBean public LoadBalancerRequestFactory loadBalancerRequestFactory( LoadBalancerClient loadBalancerClient) { return new LoadBalancerRequestFactory(loadBalancerClient, transformers); } // LoadBalancerInterceptor Bean @Configuration @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate") static class LoadBalancerInterceptorConfig { @Bean public LoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }
// @LoadBalanced RestTemplate @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final LoadBalancerInterceptor loadBalancerInterceptor) { return new RestTemplateCustomizer() { @Override public void customize(RestTemplate restTemplate) { List
list = new ArrayList<>( restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); } }; } }
}
요약: 이제 우 리 는 @ loadBalanced 의 역할 을 대체적으로 알 아야 합 니 다. 바로 RestTemplate 를 표시 하 는 역할 을 합 니 다. 서비스 가 시 작 될 때 표 시 된 RestTemplate 대상 에 LoadBalancer Interceptor 차단기 가 자동 으로 추 가 됩 니 다. 그러면 RestTemplate 가 외부 에서 http 요청 을 할 때 LoadBalancer Interceptor 의 intercept 함수 에 의 해 차단 되 고,그리고 intercept 에서 LoadBalancerClient 인터페이스 구현 클래스 execute 방법 을 호출 했 습 니 다. 우 리 는 이어서 아래 를 봅 니 다.LoadBalancerInterceptor intercept :
@Override public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
// : :http://HELLO-SERVICE/hello final URI originalUri = request.getURI(); String serviceName = originalUri.getHost(); Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution)); }
여기 LoadBalancer Client 의 실현 은 Ribbon LoadBalancer Client 입 니 다.public
T execute(String serviceId, LoadBalancerRequest request) throws IOException { // serviceId ILoadBalancer , ZoneAwareLoadBalancer
ILoadBalancer loadBalancer =//(RibbonClientConfiguration ILoadBalancer )
this.getLoadBalancer(serviceId); Server server =
this.getServer(loadBalancer);
if (server ==
null) {
throw new IllegalStateException(
"No instances available for " + serviceId); }
else {// Server RibbonServer, RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); return this.execute(serviceId, ribbonServer, request); } }
//ZoneAwareLoadBalancer Rule Server( zone , Server
// serviceId Rule IP:port Server)
protected Server getServer(ILoadBalancer loadBalancer) { return loadBalancer == null ? null : loadBalancer.chooseServer("default"); }
이어서 아래 를 본다.public
T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest request) throws IOException { Server server = null; if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) { server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer(); } if (server == null) { throw new IllegalStateException("No instances available for " + serviceId); } else { RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId); RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server); try {
// T returnVal = request.apply(serviceInstance); statsRecorder.recordStats(returnVal); return returnVal; } catch (IOException var8) { statsRecorder.recordStats(var8); throw var8; } catch (Exception var9) { statsRecorder.recordStats(var9); ReflectionUtils.rethrowRuntimeException(var9); return null; } } }
public LoadBalancerRequest
createRequest(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) { return new LoadBalancerRequest () { @Override public ClientHttpResponse apply(final ServiceInstance instance) throws Exception { HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer); if (transformers != null) { for (LoadBalancerRequestTransformer transformer : transformers) { serviceRequest = transformer.transformRequest(serviceRequest, instance); } } return execution.execute(serviceRequest, body); } }; }
ServiceRequestWrapper 대상 이 getURL 방법 을 바 꾸 었 음 을 주의해 야 합 니 다.@Override public URI getURI() { URI uri = this.loadBalancer.reconstructURI( this.instance, getRequest().getURI()); return uri; }
그래서 이곳 의 reconstructurI 는 실제 적 으로 클래스 Ribbon LoadBalancerClient 를 실현 하 는 reconstructurI 방법 을 호출 합 니 다.public URI reconstructURI(ServiceInstance instance, URI original) { Assert.notNull(instance, "instance can not be null"); String serviceId = instance.getServiceId(); RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
// server IP:port Server server = new Server(instance.getHost(), instance.getPort()); IClientConfig clientConfig = this.clientFactory.getClientConfig(serviceId); ServerIntrospector serverIntrospector = this.serverIntrospector(serviceId);
// Https URI uri = RibbonUtils.updateToHttpsIfNeeded(original, clientConfig, serverIntrospector, server);
// Server URI
return context.reconstructURIWithServer(server, uri); }
execution.execute(serviceRequest, body) InterceptingRequestExecution execute :
@Override public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException { if (this.iterator.hasNext()) { ClientHttpRequestInterceptor nextInterceptor = this.iterator.next(); return nextInterceptor.intercept(request, body, this); } else { ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod()); for (Map.Entry
> entry : request.getHeaders().entrySet()) { List values = entry.getValue(); for (String value : values) { delegate.getHeaders().add(entry.getKey(), value); } } if (body.length > 0) { StreamUtils.copy(body, delegate.getBody()); }
여기 request. getURI () 가 호출 한 것 은
ServiceRequestWrapper 의 getURL, 즉 RibbonLoadBalancerClient 의// return delegate.execute(); } } }
결론: 자, 이로써 springCloud 의 분석 은 일 단락 되 었 습 니 다. 여기 서도 부하 균형 에 대한 대강 을 제 시 했 을 뿐 상세 한 세부 사항 을 열거 하지 않 았 습 니 다. 독 자 는 대강 에 따라 세부 사항 을 대조 하여 볼 수 있 습 니 다. 시청 해 주 셔 서 감사합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.