Series of articles:
SpringCloud source series (1) – registry initialization for Eureka
SpringCloud source code series (2) – Registry Eureka service registration, renewal
SpringCloud source code series (3) – Registry Eureka crawl registry
SpringCloud source code series (4) – Registry Eureka service offline, failure, self-protection mechanism
SpringCloud source series (5) – Registry EurekaServer cluster for Eureka
SpringCloud source Code Series (6) – Summary of the Registry Eureka
SpringCloud source series (7) – load balancing Ribbon RestTemplate
SpringCloud source series (8) – load balancing Ribbon core principles
Ribbon Core Interface
Now that you’ve seen how the Ribbon core interface and the default implementation collaborate to find an instance to call, let’s take a look at some of the features and other implementation classes of each core interface.
Client configuration – IClientConfig
IClientConfig is the core interface for managing client configuration, and its default implementation class is DefaultClientConfigImpl. When creating IClientConfig, the Ribbon client sets the default connection and read timeout time to 1 second. For example, if the read time exceeds 1 second, the Ribbon returns a timeout. These two Settings need to be adjusted according to actual conditions.
@Bean
@ConditionalOnMissingBean
public IClientConfig ribbonClientConfig(a) {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
// Load the configuration
config.loadProperties(this.name);
// Connection timeout defaults to 1 second
config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
// Read timeout defaults to 1 second
config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
return config;
}
Copy the code
CommonClientConfigKey This class defines key constants for all configurations associated with the Ribbon client. You can use this class to see which configurations are available.
public abstract class CommonClientConfigKey<T> implements IClientConfigKey<T> {
public static final IClientConfigKey<String> AppName = new CommonClientConfigKey<String>("AppName") {};public static final IClientConfigKey<Integer> MaxAutoRetries = new CommonClientConfigKey<Integer>("MaxAutoRetries") {};public static final IClientConfigKey<Integer> MaxAutoRetriesNextServer = new CommonClientConfigKey<Integer>("MaxAutoRetriesNextServer") {};public static final IClientConfigKey<Boolean> OkToRetryOnAllOperations = new CommonClientConfigKey<Boolean>("OkToRetryOnAllOperations") {};public static final IClientConfigKey<Integer> ConnectTimeout = new CommonClientConfigKey<Integer>("ConnectTimeout") {};public static final IClientConfigKey<Integer> BackoffInterval = new CommonClientConfigKey<Integer>("BackoffTimeout") {};public static final IClientConfigKey<Integer> ReadTimeout = new CommonClientConfigKey<Integer>("ReadTimeout") {};//LoadBalancer Related
public static final IClientConfigKey<Boolean> InitializeNFLoadBalancer = new CommonClientConfigKey<Boolean>("InitializeNFLoadBalancer") {};public static final IClientConfigKey<String> NFLoadBalancerClassName = new CommonClientConfigKey<String>("NFLoadBalancerClassName") {};public static final IClientConfigKey<String> NFLoadBalancerRuleClassName = new CommonClientConfigKey<String>("NFLoadBalancerRuleClassName") {};public static final IClientConfigKey<String> NFLoadBalancerPingClassName = new CommonClientConfigKey<String>("NFLoadBalancerPingClassName") {};public static final IClientConfigKey<Integer> NFLoadBalancerPingInterval = new CommonClientConfigKey<Integer>("NFLoadBalancerPingInterval") {};public static final IClientConfigKey<Integer> NFLoadBalancerMaxTotalPingTime = new CommonClientConfigKey<Integer>("NFLoadBalancerMaxTotalPingTime") {};public static final IClientConfigKey<String> NFLoadBalancerStatsClassName = new CommonClientConfigKey<String>("NFLoadBalancerStatsClassName") {};public static final IClientConfigKey<String> NIWSServerListClassName = new CommonClientConfigKey<String>("NIWSServerListClassName") {};public static final IClientConfigKey<String> ServerListUpdaterClassName = new CommonClientConfigKey<String>("ServerListUpdaterClassName") {};public static final IClientConfigKey<String> NIWSServerListFilterClassName = new CommonClientConfigKey<String>("NIWSServerListFilterClassName") {};public static final IClientConfigKey<Integer> ServerListRefreshInterval = new CommonClientConfigKey<Integer>("ServerListRefreshInterval") {};// ...
}
Copy the code
Going into DefaultClientConfigImpl, you can see that each configuration in CommonClientConfigKey corresponds to a default value. When the configuration is loaded, if the user does not customize the configuration, the default configuration is used.
public class DefaultClientConfigImpl implements IClientConfig {
public static final String DEFAULT_NFLOADBALANCER_PING_CLASSNAME = "com.netflix.loadbalancer.DummyPing"; // DummyPing.class.getName();
public static final String DEFAULT_NFLOADBALANCER_RULE_CLASSNAME = "com.netflix.loadbalancer.AvailabilityFilteringRule";
public static final String DEFAULT_NFLOADBALANCER_CLASSNAME = "com.netflix.loadbalancer.ZoneAwareLoadBalancer";
public static final int DEFAULT_MAX_AUTO_RETRIES_NEXT_SERVER = 1;
public static final int DEFAULT_MAX_AUTO_RETRIES = 0;
public static final int DEFAULT_BACKOFF_INTERVAL = 0;
public static final int DEFAULT_READ_TIMEOUT = 5000;
public static final int DEFAULT_CONNECTION_MANAGER_TIMEOUT = 2000;
public static final int DEFAULT_CONNECT_TIMEOUT = 2000;
public static final String DEFAULT_SEVER_LIST_CLASS = "com.netflix.loadbalancer.ConfigurationBasedServerList";
public static final String DEFAULT_SERVER_LIST_UPDATER_CLASS = "com.netflix.loadbalancer.PollingServerListUpdater";
public String getDefaultNfloadbalancerPingClassname(a) {
return DEFAULT_NFLOADBALANCER_PING_CLASSNAME;
}
public String getDefaultNfloadbalancerRuleClassname(a) {
return DEFAULT_NFLOADBALANCER_RULE_CLASSNAME;
}
public String getDefaultNfloadbalancerClassname(a) {
return DEFAULT_NFLOADBALANCER_CLASSNAME;
}
public int getDefaultMaxRetriesPerServerPrimeConnection(a) {
return DEFAULT_MAX_RETRIES_PER_SERVER_PRIME_CONNECTION;
}
public Boolean getDefaultEnablePrimeConnections(a) {
return DEFAULT_ENABLE_PRIME_CONNECTIONS;
}
//....
}
Copy the code
You can also customize the configuration in the configuration file, such as configuring timeout and retry:
# global configuration
ribbon:
Client read timeout
ReadTimeout: 3000
Client connection timeout
ConnectTimeout: 3000
If set to true, retry all types, such as POST, PUT, and DELETE
OkToRetryOnAllOperations: false
# retries
MaxAutoRetries: 1
Retry a maximum of several instances
MaxAutoRetriesNextServer: 1
# Only for the Demo-producer client
demo-producer:
ribbon:
Client read timeout
ReadTimeout: 5000
Client connection timeout
ConnectTimeout: 3000
Copy the code
Balancing policy – IRule
IRule is the policy rule class that ultimately selects the Server. The core interface is Choose.
public interface IRule{
/ / select Server
public Server choose(Object key);
/ / set ILoadBalancer
public void setLoadBalancer(ILoadBalancer lb);
/ / get ILoadBalancer
public ILoadBalancer getLoadBalancer(a);
}
Copy the code
The Ribbon provides a wide range of load balancing policies. You can also configure a load balancing policy. Here are the IRule balancing policies that the Ribbon provides.
Service check – IPing
IPing is used to periodically check the availability of the Server. It provides only one interface to determine whether the Server is alive or not:
public interface IPing {
public boolean isAlive(Server server);
}
Copy the code
IPing also provides a variety of policies to choose from. Here is the overall IPing architecture:
Get the service list – ServerList
ServerList provides two interfaces, one is to get the Server list for the first time, one is to update the Server list, GetUpdatedListOfServers will be called every 30 seconds by the Loadbalancer to update allServerList.
public interface ServerList<T extends Server> {
public List<T> getInitialListOfServers(a);
/** * Return updated list of servers. This is called say every 30 secs * (configurable) by the Loadbalancer's Ping cycle * /
public List<T> getUpdatedListOfServers(a);
}
Copy the code
ServerList also provides multiple implementations. The ServerList architecture is as follows:
Filtering service – ServerListFilter
ServerListFilter provides an interface to filter out available servers.
public interface ServerListFilter<T extends Server> {
public List<T> getFilteredListOfServers(List<T> servers);
}
Copy the code
The ServerListFilter architecture is as follows:
Service list update – ServerListUpdater
ServerListUpdater has multiple interfaces. The most important one is to start a scheduled task and call updateAction to update the allServerList.
public interface ServerListUpdater {
/** * an interface for the updateAction that actually executes a server list update */
public interface UpdateAction {
void doUpdate(a);
}
/** * start the serverList updater with the given update action * This call should be idempotent. */
void start(UpdateAction updateAction);
}
Copy the code
There are two implementation classes by default:
Load balancer – ILoadBalancer
ILoadBalancer is the core interface for load balancing service selection. It provides the following interface for obtaining the Server list and selecting the Server based on the client name.
public interface ILoadBalancer {
/ / add a Server
public void addServers(List<Server> newServers);
// Select a Server based on the key
public Server chooseServer(Object key);
// Get the list of surviving servers, return the upServerList
public List<Server> getReachableServers(a);
// Get the list of all servers, return allServerList
public List<Server> getAllServers(a);
}
Copy the code
The architecture of ILoadBalancer is as follows:
Ribbon configuration classes
There are many configuration classes in the Ribbon. Here we summarize the configuration classes in the Ribbon. We look at the configuration order of each class and what is configured in it.
EurekaClientAutoConfiguration
First is the Eureka EurekaClientAutoConfiguration client configuration class, the main configuration automation configuration class Ribbon EurekaClient as needed.
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = { "org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration", "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration", "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration", "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" })
public class EurekaClientAutoConfiguration {
/ /...
}
Copy the code
RibbonAutoConfiguration
The Ribbon automatic configuration class is followed by RibbonAutoConfiguration, which is mainly configured as follows:
SpringClientFactory
: Manages the Ribbon client context.LoadBalancerClient
: load balancing the client, the default implementation class for RibbonLoadBalancerClient (is actually in RibbonClientConfiguration configuration).PropertiesFactory
: used to determine whether a configuration file defines the core interface implementation class, such as NFLoadBalancerClassName, NFLoadBalancerPingClassName, etc.RibbonApplicationContextInitializer
: This class is used to initialize the Ribbon client context at boot time when hungry configuration is enabled.
package org.springframework.cloud.netflix.ribbon;
@Configuration
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
/ / after EurekaClientAutoConfiguration configuration
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
/ / before LoadBalancerAutoConfiguration, AsyncLoadBalancerAutoConfiguration configuration
@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class })
@EnableConfigurationProperties({ RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class })
public class RibbonAutoConfiguration {
@Autowired(required = false)
private List<RibbonClientSpecification> configurations = new ArrayList<>();
@Autowired
private RibbonEagerLoadProperties ribbonEagerLoadProperties;
@Bean
public HasFeatures ribbonFeature(a) {
return HasFeatures.namedFeature("Ribbon", Ribbon.class);
}
@Bean
@ConditionalOnMissingBean
public SpringClientFactory springClientFactory(a) {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient(a) {
return new RibbonLoadBalancerClient(springClientFactory());
}
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) {
return new RibbonLoadBalancedRetryFactory(clientFactory);
}
@Bean
@ConditionalOnMissingBean
public PropertiesFactory propertiesFactory(a) {
return new PropertiesFactory();
}
@Bean
@ConditionalOnProperty("ribbon.eager-load.enabled")
public RibbonApplicationContextInitializer ribbonApplicationContextInitializer(a) {
return newRibbonApplicationContextInitializer(springClientFactory(), ribbonEagerLoadProperties.getClients()); }}Copy the code
LoadBalancerAutoConfiguration
Then the load balancer configuration class LoadBalancerAutoConfiguration, this class is to create a load balancing interceptor LoadBalancerInterceptor, and added to the RestTemplae interceptors.
package org.springframework.cloud.client.loadbalancer;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
// Customize the RestTemplate
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for(RestTemplateCustomizer customizer : customizers) { customizer.customize(restTemplate); }}}); }@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// Create RestTemplate interceptor
@Bean
public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
// RestTemplate customizer
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = newArrayList<>(restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; }}}Copy the code
RibbonClientConfiguration
After is the default Ribbon RibbonClientConfiguration client configuration class, this class is mainly configured with Ribbon core the default implementation of the interface.
IClientConfig
: Ribbon client configuration class. Default implementation is DefaultClientConfigImpl.IRule
: Load balancing policy rule component, the default implementation is ZoneAvoidanceRule.IPing
The default implementation is DummyPing, which always returns true.ServerList
Components: access to the Server, the default implementation class for ConfigurationBasedServerList, obtained from the config file.ServerListUpdater
: Server list update component, default implementation class is PollingServerListUpdater.ServerListFilter
: filter available in the Server list, the default implementation class for ZonePreferenceServerListFilter.RibbonLoadBalancerContext
: load balancing client.RetryHandler
: retry processor, the default implementation class for DefaultLoadBalancerRetryHandler.
package org.springframework.cloud.netflix.ribbon;
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class })
public class RibbonClientConfiguration {
public static final int DEFAULT_CONNECT_TIMEOUT = 1000;
public static final int DEFAULT_READ_TIMEOUT = 1000;
public static final boolean DEFAULT_GZIP_PAYLOAD = true;
@RibbonClientName
private String name = "client";
@Autowired
private PropertiesFactory propertiesFactory;
@Bean
@ConditionalOnMissingBean
public IClientConfig ribbonClientConfig(a) {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.loadProperties(this.name);
config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
return config;
}
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, name)) {
return this.propertiesFactory.get(IPing.class, config, name);
}
return new DummyPing();
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerList.class, name)) {
return this.propertiesFactory.get(ServerList.class, config, name);
}
ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
return new PollingServerListUpdater(config);
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList
serverList, ServerListFilter
serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater)
{
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
return this.propertiesFactory.get(ServerListFilter.class, config, name);
}
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
@Bean
@ConditionalOnMissingBean
public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer, IClientConfig config, RetryHandler retryHandler) {
return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
}
@Bean
@ConditionalOnMissingBean
public RetryHandler retryHandler(IClientConfig config) {
return new DefaultLoadBalancerRetryHandler(config);
}
@Bean
@ConditionalOnMissingBean
public ServerIntrospector serverIntrospector(a) {
return newDefaultServerIntrospector(); }}Copy the code
RibbonEurekaAutoConfiguration
Ribbon Eureka automation configuration class RibbonEurekaAutoConfiguration, judge whether to enable Ribbon Eureka, triggering EurekaRibbonClientConfiguration configuration class.
package org.springframework.cloud.netflix.ribbon.eureka;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnRibbonAndEurekaEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = EurekaRibbonClientConfiguration.class)
public class RibbonEurekaAutoConfiguration {}Copy the code
EurekaRibbonClientConfiguration
Enabled by default Ribbon under the condition of Eureka, will use the Ribbon Eureka EurekaRibbonClientConfiguration client configuration class:
IPing
: The default implementation class DummyPing is replaced by NIWSDiscoveryPing, which determines whether the Server is alive by checking whether the InstanceInfo status is UP.ServerList
: Replace the default implementation class ConfigurationBasedServerList, DomainExtractingServerList instead, actual it is DiscoveryEnabledNIWSServerList, Get the Server list from EurekaClient.
package org.springframework.cloud.netflix.ribbon.eureka;
@Configuration(proxyBeanMethods = false)
public class EurekaRibbonClientConfiguration {
@Value("${ribbon.eureka.approximateZoneFromHostname:false}")
private boolean approximateZoneFromHostname = false;
@RibbonClientName
private String serviceId = "client";
@Autowired(required = false)
private EurekaClientConfig clientConfig;
@Autowired(required = false)
private EurekaInstanceConfig eurekaConfig;
@Autowired
private PropertiesFactory propertiesFactory;
public EurekaRibbonClientConfiguration(a) {}public EurekaRibbonClientConfiguration(EurekaClientConfig clientConfig, String serviceId, EurekaInstanceConfig eurekaConfig, boolean approximateZoneFromHostname) {
this.clientConfig = clientConfig;
this.serviceId = serviceId;
this.eurekaConfig = eurekaConfig;
this.approximateZoneFromHostname = approximateZoneFromHostname;
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
return this.propertiesFactory.get(IPing.class, config, serviceId);
}
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
ping.initWithNiwsConfig(config);
return ping;
}
@Bean
@ConditionalOnMissingBean
publicServerList<? > ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
return this.propertiesFactory.get(ServerList.class, config, serviceId);
}
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
returnserverList; }}Copy the code
The module to which each configuration class belongs
Spring – the cloud – netflix – eureka – the client:
- org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
- org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
- org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientConfiguration
Spring – the cloud – netflix – ribbon:
- org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration
- org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
Spring – the cloud – Commons:
- org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration
Client Ribbon customization
IRule, IPing, created in the RibbonClientConfiguration ServerList < Server >, ServerListFilter < Server > ILoadBalancer, IsSet check whether an implementation class of the corresponding type has been configured. If no implementation class of the corresponding type has been configured, the default implementation class is used.
That is, for a particular service, these classes can be customized or configured to specify other implementation classes. In this section we take a look at how the Ribbon customizes some configurations.
The client Ribbon provides three configurations: Global policy, Annotation based, and Configuration file. The priorities of these configurations are As follows: Configuration File > @RibbonClients Annotation > Global > Default.
Global Policy Configuration
If you want to change the configuration globally, you need to add a configuration class like this:
@Configuration
public class GlobalRibbonConfiguration {
@Bean
public IRule ribbonRule(a) {
return new RandomRule();
}
@Bean
public IPing ribbonPing(a) {
return newNoOpPing(); }}Copy the code
Annotation-based configuration
If you want to customize the configuration for a service, you can configure a service specific configuration class by using @RibbonClients.
We need to define a service configuration class:
@Configuration
public class ProducerRibbonConfiguration {
@Bean
public IRule ribbonRule(a) {
return new RandomRule();
}
@Bean
public IPing ribbonPing(a) {
return newNoOpPing(); }}Copy the code
Use the @RibbonClients annotation to specify a specific configuration class for the service, and remove it side by side so that Spring cannot scan it, otherwise it becomes a global configuration.
@RibbonClients({ @RibbonClient(name = "demo-producer", configuration = ProducerRibbonConfiguration.class) })
@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ProducerRibbonConfiguration.class) })
public class XxxConfiguration {}Copy the code
Configuration file Configuration
The configuration file is in the format of < service name >. Ribbon.< properties > :
demo-producer:
ribbon:
# ILoadBalancer
NFLoadBalancerClassName: com.netflix.loadbalancer.NoOpLoadBalancer
# IRule
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# IPing
NFLoadBalancerPingClassName:
# ServerList<Server>
NIWSServerListClassName:
# ServerListFilter<Server>
NIWSServerListFilterClassName:
Copy the code
The Ribbon context hunger loads
As mentioned in the previous article, when components such as ILoadBalancer are retrieved from SpringClientFactory, they are created at run time. The Ribbon client application context is lazily loaded by default. The context is not loaded at startup, but initialized at the first call.
If you want the Ribbon client to be initialized at startup, you can specify the Ribbon client name and load the context of the configuration item at startup:
ribbon:
eager-load:
enabled: true
Understand the initialized client name at startup
clients: demo-producer,demo-xxx
Copy the code
In RibbonAutoConfiguration configuration classes can be found in the configuration, the hunger if opens the hunger to load, will create RibbonApplicationContextInitializer to initialized at startup context.
@Bean
@ConditionalOnProperty("ribbon.eager-load.enabled")
public RibbonApplicationContextInitializer ribbonApplicationContextInitializer(a) {
return new RibbonApplicationContextInitializer(springClientFactory(), ribbonEagerLoadProperties.getClients());
}
public class RibbonApplicationContextInitializer implements ApplicationListener<ApplicationReadyEvent> {
private final SpringClientFactory springClientFactory;
// List of Ribbon client names
private final List<String> clientNames;
public RibbonApplicationContextInitializer(SpringClientFactory springClientFactory, List<String> clientNames) {
this.springClientFactory = springClientFactory;
this.clientNames = clientNames;
}
protected void initialize(a) {
if(clientNames ! =null) {
for (String clientName : clientNames) {
// Initialize the context in advance
this.springClientFactory.getContext(clientName); }}}@Override
public void onApplicationEvent(ApplicationReadyEvent event) { initialize(); }}Copy the code
The Ribbon is used independently of Eureka
By default, the Ribbon client retrieves the service list from EurekaClient. The Ribbon client indirectly reads the service registry from EurekaClient for dynamic load balancing. However, if you don’t want to read from EurekaClient, you can disable the Eureka feature in the Ribbon. You can disable Eureka in the Ribbon as follows:
ribbon:
eureka:
enabled: false
Copy the code
How does ribbon. Eureka. Enabled disable Eureka? See RibbonEurekaAutoConfiguration:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnRibbonAndEurekaEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = EurekaRibbonClientConfiguration.class)
public class RibbonEurekaAutoConfiguration {}Copy the code
This configuration class by @ RibbonClients specifies the default client configuration class for EurekaRibbonClientConfiguration, but the effect is the premise of @ ConditionalOnRibbonAndEurekaEnabled, If Ribbon Eureka is enabled, set Ribbon. Eureka. Enabled =false to disable Ribbon Eureka.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
Class OnRibbonAndEurekaEnabledCondition / / conditions
@Conditional(ConditionalOnRibbonAndEurekaEnabled.OnRibbonAndEurekaEnabledCondition.class)
public @interface ConditionalOnRibbonAndEurekaEnabled {
class OnRibbonAndEurekaEnabledCondition extends AllNestedConditions {
OnRibbonAndEurekaEnabledCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
/ / introduces categories: DiscoveryEnabledNIWSServerList
@ConditionalOnClass(DiscoveryEnabledNIWSServerList.class)
// There is a bean object: SpringClientFactory
@ConditionalOnBean(SpringClientFactory.class)
// ribbon.eureka.enabled=true
@ConditionalOnProperty(value = "ribbon.eureka.enabled", matchIfMissing = true)
static class Defaults {}// There is a bean object: EurekaClient
@ConditionalOnBean(EurekaClient.class)
static class EurekaBeans {}// eureka.client.enabled=true
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@ConditionalOnDiscoveryEnabled
static class OnEurekaClientEnabled {}}}Copy the code
If you want to get the list of services from other places, you can customize the interface ServerList
to get it, or you can set the address list in the configuration file:
<client-name>:
ribbon:
listOfServers: http://10.215.0.92:8010,http://10.215.0.92:8011
Copy the code