Ribbon auto configuration class
Based on the automatic configuration function provided by Spring Boot, the Ribbon automatically configured classes are available at org.com springframework. cloud. netflix. The RibbonClientConfiguration and RibbonAutoConfiguration configuration classes of the Ribbon package.
RibbonAutoConfiguration
RibbonAutoConfiguration is equivalent to global configuration. It mainly loads Ribbon client factory, configuration class factory, retry mechanism factory, etc. this configuration class will be loaded when it is started.
First, take a look at the comments on the RibbonAutoConfiguration configuration class:
// Marked as configuration class Bean @Configuration // Inject Bean conditions, and the RibbonClassesConditions class determines whether to inject the Bean @Conditional({RibbonAutoConfiguration.RibbonClassesConditions.class}) // @RibbonClients provides default configuration for all Ribbon clients, @ RibbonClients marks that this class is registered as a RibbonClientSpecification @RibbonClients // Load the current class after loading the configured class @AutoConfigureAfter( name = {"org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"} ) // Load the current class before loading the configured class @AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class}) // Make RibbonEagerLoadProperties and ServerIntrospectorProperties configuration classes effective @EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
This class has two properties and uses @ Autowired injection
@Autowired( required = false ) // List collection, type RibbonClientSpecification, and inject the configuration class using @ RibbonClients. private List<RibbonClientSpecification> configurations = new ArrayList(); // Ribbon's hungry load mode configuration class. Ribbon's Client for Client load balancing does not start when the service is started // The corresponding Client is created only when it is called, and the load starvation mode is enabled, which can be created in advance. @Autowired private RibbonEagerLoadProperties ribbonEagerLoadProperties;
Next, take a look at the Bean objects injected by this configuration class:
// HasFeatures can view some features of the system startup to understand the system characteristics. @Bean public HasFeatures ribbonFeature() { return HasFeatures.namedFeature("Ribbon", Ribbon.class); } // Spring creates a factory for Ribbon clients, load balancers, and client configuration instances @Bean @ConditionalOnMissingBean public SpringClientFactory springClientFactory() { SpringClientFactory factory = new SpringClientFactory(); factory.setConfigurations(this.configurations); return factory; } // LoadBalancerClient is a load balancer client provided by spring cloud. It can query all services and select one @Bean @ConditionalOnMissingBean({LoadBalancerClient.class}) public LoadBalancerClient loadBalancerClient() { return new RibbonLoadBalancerClient(this.springClientFactory()); } // Ribbon retry factory @Bean @ConditionalOnClass( name = {"org.springframework.retry.support.RetryTemplate"} ) @ConditionalOnMissingBean public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) { return new RibbonLoadBalancedRetryFactory(clientFactory); } // It is used to obtain the client configuration class, such as interface com netflix. loadbalancer. IRule rule configuration class, corresponding to an attribute = < NFLoadBalancerRuleClassName > @Bean @ConditionalOnMissingBean public PropertiesFactory propertiesFactory() { return new PropertiesFactory(); } // If eager load mode is configured, the RibbonApplicationContextInitializer context initialization object is registered @Bean @ConditionalOnProperty({"ribbon.eager-load.enabled"}) public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() { return new RibbonApplicationContextInitializer(this.springClientFactory(), this.ribbonEagerLoadProperties.getClients()); }
RibbonClientConfiguration
RibbonClientConfiguration is the Ribbon client related configuration. This class will not be loaded until the first Feign client request is executed.
For example, if the Feign client is currently order service and it makes a request for the first time, it will enter the method to obtain the client configuration:
Then get the context of the changed client in the NamedContextFactory. If not, it will be created.
protected AnnotationConfigApplicationContext getContext(String name) { // Does the current context contain the client order service if (!this.contexts.containsKey(name)) { synchronized(this.contexts) { // If not, create and place if (!this.contexts.containsKey(name)) { this.contexts.put(name, this.createContext(name)); } } } // There is a direct return return (AnnotationConfigApplicationContext)this.contexts.get(name); }
Finally, the createContext method of NamedContextFactory is called to create a context for each client.
Through the NamedContextFactory mechanism, different sub applicationcontexts are created according to different applications, so as to isolate and not affect each other. Each Feign client is configured with different application contexts, so that each different client can use different configurations and different beans.
After the createContext method creates the Context of the client and enters the refresh, it will start loading the beans, pre and post processors and other processes directly required by the current Context. RibbonClientConfiguration is loaded at this time.
// Create a Context object for a proxy object corresponding to the @ FeignClient interface before obtaining it protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); // Query the configuration class of @ RibbonClients in RibbonAutoConfiguration if (this.configurations.containsKey(name)) { // If there is a configuration with the name of the current client in the configuration class, add the configuration and register it in the context Class[] var3 = ((NamedContextFactory.Specification)this.configurations.get(name)).getConfiguration(); int var4 = var3.length; for(int var5 = 0; var5 < var4; ++var5) { Class<?> configuration = var3[var5]; context.register(new Class[]{configuration}); } } // The configuration class of @ RibbonClients is recycled Iterator var9 = this.configurations.entrySet().iterator(); while(true) { Entry entry; do { if (!var9.hasNext()) { // register context.register(new Class[]{PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType}); context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName, Collections.singletonMap(this.propertyName, name))); if (this.parent != null) { context.setParent(this.parent); context.setClassLoader(this.parent.getClassLoader()); } context.setDisplayName(this.generateDisplayName(name)); // Refresh context context.refresh(); return context; } entry = (Entry)var9.next(); // The configuration class does not start with default At the beginning, it enters the do loop. There is no } while(!((String)entry.getKey()).startsWith("default.")); Class[] var11 = ((NamedContextFactory.Specification)entry.getValue()).getConfiguration(); int var12 = var11.length; // Cycle through the default configuration and register for(int var7 = 0; var7 < var12; ++var7) { Class<?> configuration = var11[var7]; context.register(new Class[]{configuration}); } } }
You can see that there are two @ RibbonClients configuration classes by default:
After creating the context, you can see the context information of the current client.
The RibbonClientConfiguration class uses @ Import to Import other configuration classes.
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
The properties of the RibbonClientConfiguration class are as follows:
// The default connection timeout is 1 second public static final int DEFAULT_CONNECT_TIMEOUT = 1000; // The default read timeout is 1 second public static final int DEFAULT_READ_TIMEOUT = 1000; public static final boolean DEFAULT_GZIP_PAYLOAD = true; // @Ribbonclientname ribbonclientname @RibbonClientName private String name = "client"; // Configuration factory, injected by RibbonAutoConfiguration @Autowired private PropertiesFactory propertiesFactory;
Finally, let's take a look at the beans injected by RibbonClientConfiguration:
// Current client configuration @Bean @ConditionalOnMissingBean public IClientConfig ribbonClientConfig() { // Default configuration class DefaultClientConfigImpl config = new DefaultClientConfigImpl(); // load configuration config.loadProperties(this.name); // set configuration config.set(CommonClientConfigKey.ConnectTimeout, 1000); config.set(CommonClientConfigKey.ReadTimeout, 1000); config.set(CommonClientConfigKey.GZipPayload, true); return config; } // Load the load balancing algorithm. The default is ZoneAvoidanceRule polling. @Bean @ConditionalOnMissingBean public IRule ribbonRule(IClientConfig config) { if (this.propertiesFactory.isSet(IRule.class, this.name)) { return (IRule)this.propertiesFactory.get(IRule.class, config, this.name); } else { ZoneAvoidanceRule rule = new ZoneAvoidanceRule(); rule.initWithNiwsConfig(config); return rule; } } // Ping detection service health status @Bean @ConditionalOnMissingBean public IPing ribbonPing(IClientConfig config) { return (IPing)(this.propertiesFactory.isSet(IPing.class, this.name) ? (IPing)this.propertiesFactory.get(IPing.class, config, this.name) : new DummyPing()); } // Ribbon's service list @Bean @ConditionalOnMissingBean public ServerList<Server> ribbonServerList(IClientConfig config) { if (this.propertiesFactory.isSet(ServerList.class, this.name)) { return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.name); } else { ConfigurationBasedServerList serverList = new ConfigurationBasedServerList(); serverList.initWithNiwsConfig(config); return serverList; } } // Service list Updater @Bean @ConditionalOnMissingBean public ServerListUpdater ribbonServerListUpdater(IClientConfig config) { return new PollingServerListUpdater(config); } // Load balancer ILoadBalancer @Bean @ConditionalOnMissingBean public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) { return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.class, this.name) ? (ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name) : new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater)); } // ServerListFilter service list filter of the five components of Ribbon's LoadBalancer @Bean @ConditionalOnMissingBean public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) { if (this.propertiesFactory.isSet(ServerListFilter.class, this.name)) { return (ServerListFilter)this.propertiesFactory.get(ServerListFilter.class, config, this.name); } else { ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter(); filter.initWithNiwsConfig(config); return filter; } } // Load balancer context @Bean @ConditionalOnMissingBean public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer, IClientConfig config, RetryHandler retryHandler) { return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler); } // Retry processor @Bean @ConditionalOnMissingBean public RetryHandler retryHandler(IClientConfig config) { return new DefaultLoadBalancerRetryHandler(config); } // Service interceptor @Bean @ConditionalOnMissingBean public ServerIntrospector serverIntrospector() { return new DefaultServerIntrospector(); } // Post Processors @PostConstruct public void preprocess() { RibbonUtils.setRibbonProperty(this.name, CommonClientConfigKey.DeploymentContextBasedVipAddresses.key(), this.name); }
summary
Project startup = > RibbonAutoConfiguration (load factory class, default configuration) = > first access = > proxy client = > initialize the client context = > RibbonClientConfiguration (load service list, filter, interceptor, client configuration, etc.) = > process the request.