This is the 15th day of my participation in Gwen Challenge
One, foreword
Start with a demo, then analyze the ribbon flow, and finally write down the source code.
(1)Ribbon + RestTemplate
case
A brief introduction to the implementation principle:
- Through the
RestTemplate
To add@LoadBalanced
Adding interceptors - Interceptor through
Ribbon
Selecting a service instance - Then replace the service name in the request address with
Ribbon
Of the selected service instanceIP
And port
pom.xml
The configuration file
<! 'eureka-client' in 'SpringCloud' -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.2. RELEASE</version>
</dependency>
<! -- Directly import 'ribbon' -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Copy the code
RestTemplate
The use of
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(a) {
return newRestTemplate(); }}Copy the code
(2) DiagramRibbon
process
The general process is shown as follows:
The general process can be divided into:
- Note: automatic assembly
LoadBalancerAutoConfiguration
- In the auto-configuration class, is
RestTemplate
Adding interceptorsLoadBalancerInterceptor
- Gets in the interceptor after invoking the request
host
And, inLoadBalancerClient
In thehost
The information is transformed to get the real server address. LoadBalancerClient
In the fromEureka client
Get a list of service instances and then include load balancing rulesIRule
, which is selected to initiate the callserver
.- To be responsible for
HTTP
Component of communicationLoadBalancerRequest
Execute trueHTTP
The request.
Initialize the source code
It is mainly divided into:
- Initialization: annotations, autowage, adding interceptors
- Request initialization
spring-cloud
与ribbon
Default for integrationILoadBalancer
1) Initialization: annotations, auto-assembly, adding interceptors
This process is mainly divided into three parts:
- from
@LoadBalanced
Annotation of LoadBalancerAutoConfiguration
Automatically.RestTemplate
Setting up interceptors
The flow chart is as follows:
Detailed process source code is as follows:
- From the first
@LoadBalanced
Start with notes:
On the RestTemplate, annotate @loadBalance.
/ / positioning: org. Springframework. Cloud. Client. The loadbalancer
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
Copy the code
LoadBalancerAutoConfiguration
Automatically.
For Spring Boot and Spring Cloud classes, look directly for XXXAutoConfiguration:
/ / positioning: org. Springframework. Cloud. Client. The loadbalancer
@Configuration
@ConditionalOnClass(RestTemplate.class) // The class is loaded when it exists
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
// Put the user-created 'RestTemplate' here
@LoadBalanced
@Autowired(required = false)
privateList<RestTemplate> restTemplates = Collections.emptyList(); . .// Use 'RestTemplateCustomizer' to customize each 'RestTemplate'
// Set each 'RestTemplate' to the 'Interceptor'
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated(a) {
for (RestTemplate restTemplate :
LoadBalancerAutoConfiguration.this.restTemplates) {
for(RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); }}}}; }... .// 3. Add interceptor to RestTemplate
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {... ./ / create RestTemplateCustomizer
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
// Add interceptors to each RestTemplate
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
// The interceptor is customized with RestTemplateCustomizerrestTemplate.setInterceptors(list); }}; }}}Copy the code
A little wayLoadBalancerInterceptor
:
-
By calling the RestTemplateCustomizer. Customize () method to add interceptors to RestTemplate LoadBalancerInterceptor.
-
Load balancing is implemented in the LoadBalancerInterceptor.
2) Request initialization
The main process is divided into:
-
Interceptor handling: address translation
-
LoadBalancerClient process: Implements load balancing
-
Interceptor handling: address translation
The general process is shown as follows:
RestTemplate. GetForObject (” http://serviceA/hello “) into: restTemplate. GetForObject (” http://172.18.1.24:8080/hello “).
/ / positioning: org. Springframework. Cloud. Client. The loadbalancer
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
privateLoadBalancerRequestFactory requestFactory; . .// Replace host here with the actual IP :port
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
// Hand it over to LoadBalancerClient to handle the real HTTP request
// The real IRule implementation logic will be performed, using load balancing rules to filter out suitable service instances
return this.loadBalancer .execute(serviceName, requestFactory.createRequest(request, body, execution)); }}Copy the code
-
LoadBalancerClient
Processing to achieve load balancingThe interceptor is really just a simple wrapper, handing the request directly to the LoadBalancerClient to execute the item’s request.
public class RibbonLoadBalancerClient implements LoadBalancerClient {
privateSpringClientFactory clientFactory; . .@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request)
throws IOException {
// Find the load balancer corresponding to the service
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
/ / is called loadBalancer. ChooseServer method
// The server already contains a specific IP address and portServer server = getServer(loadBalancer); . .// Execute the real HTTP request
returnexecute(serviceId, ribbonServer, request); }... . }Copy the code
Then thisRibbonLoadBalancerClient
When was it initialized?
Find RibbonAutoConfiguration
/ / location: org.springframework.cloud.net flix. Ribbon
@Configuration
@ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})
@RibbonClients
/ / to perform after EurekaClientAutoConfiguration, namely eureka - client executed after initialization is complete.
@AutoConfigureAfter( name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
/ / before LoadBalancerAutoConfiguration execution
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {... . }Copy the code
In addition,ribbon
Package structure, as follows:
Ribbon - 2.2.5. Jar
:ribbon
Some of the core componentsRibbon - transport - 2.2.5. Jar
Based on:netty
A particularly low-level process of encapsulationhttp
,tcp
,udp
Components of network communication for various protocolsRibbon - core - 2.2.5. Jar
:ribbon
Basic general code componentsRibbon httpclient -- 2.2.5. Jar
Is:ribbon
At the bottom of thehttp
Some components of network communicationRibbon loadbalancer -- 2.2.5. Jar
Are:ribbon
The core of the originalAPI