本文主要研究一下spring cloud netflix ribbon的eager load

RibbonAutoConfiguration

spring-cloud-netflix-ribbon-2.1.1.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java

@Configuration@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)@RibbonClients@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")@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() {        return HasFeatures.namedFeature("Ribbon", Ribbon.class);    }    @Bean    public SpringClientFactory springClientFactory() {        SpringClientFactory factory = new SpringClientFactory();        factory.setConfigurations(this.configurations);        return factory;    }    @Bean    @ConditionalOnMissingBean(LoadBalancerClient.class)    public LoadBalancerClient loadBalancerClient() {        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() {        return new PropertiesFactory();    }    @Bean    @ConditionalOnProperty("ribbon.eager-load.enabled")    public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {        return new RibbonApplicationContextInitializer(springClientFactory(),                ribbonEagerLoadProperties.getClients());    }    @Configuration    @ConditionalOnClass(HttpRequest.class)    @ConditionalOnRibbonRestClient    protected static class RibbonClientHttpRequestFactoryConfiguration {        @Autowired        private SpringClientFactory springClientFactory;        @Bean        public RestTemplateCustomizer restTemplateCustomizer(                final RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory) {            return restTemplate -> restTemplate                    .setRequestFactory(ribbonClientHttpRequestFactory);        }        @Bean        public RibbonClientHttpRequestFactory ribbonClientHttpRequestFactory() {            return new RibbonClientHttpRequestFactory(this.springClientFactory);        }    }    // TODO: support for autoconfiguring restemplate to use apache http client or okhttp    @Target({ ElementType.TYPE, ElementType.METHOD })    @Retention(RetentionPolicy.RUNTIME)    @Documented    @Conditional(OnRibbonRestClientCondition.class)    @interface ConditionalOnRibbonRestClient {    }    private static class OnRibbonRestClientCondition extends AnyNestedCondition {        OnRibbonRestClientCondition() {            super(ConfigurationPhase.REGISTER_BEAN);        }        @Deprecated // remove in Edgware"        @ConditionalOnProperty("ribbon.http.client.enabled")        static class ZuulProperty {        }        @ConditionalOnProperty("ribbon.restclient.enabled")        static class RibbonProperty {        }    }    /**     * {@link AllNestedConditions} that checks that either multiple classes are present.     */    static class RibbonClassesConditions extends AllNestedConditions {        RibbonClassesConditions() {            super(ConfigurationPhase.PARSE_CONFIGURATION);        }        @ConditionalOnClass(IClient.class)        static class IClientPresent {        }        @ConditionalOnClass(RestTemplate.class)        static class RestTemplatePresent {        }        @ConditionalOnClass(AsyncRestTemplate.class)        static class AsyncRestTemplatePresent {        }        @ConditionalOnClass(Ribbon.class)        static class RibbonPresent {        }    }}
  • RibbonAutoConfiguration启用了RibbonEagerLoadProperties、ServerIntrospectorProperties两个配置,这里主要是注册了SpringClientFactory,创建LoadBalancerClient、LoadBalancedRetryFactory、RibbonApplicationContextInitializer、RestTemplateCustomizer及RibbonClientHttpRequestFactory

RibbonApplicationContextInitializer

spring-cloud-netflix-ribbon-2.1.1.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonApplicationContextInitializer.java

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() {        if (clientNames != null) {            for (String clientName : clientNames) {                this.springClientFactory.getContext(clientName);            }        }    }    @Override    public void onApplicationEvent(ApplicationReadyEvent event) {        initialize();    }}
  • RibbonApplicationContextInitializer实现了ApplicationListener接口,其响应ApplicationReadyEvent事件执行initialize操作,这里主要是挨个对配置的clientNames执行springClientFactory.getContext(clientName)操作

SpringClientFactory

spring-cloud-netflix-ribbon-2.1.1.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/SpringClientFactory.java

public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> {    //......    protected AnnotationConfigApplicationContext getContext(String name) {        return super.getContext(name);    }    //......}
  • SpringClientFactory的getContext方法调用了父类NamedContextFactory的getContext

NamedContextFactory

spring-cloud-context-2.2.0.M1-sources.jar!/org/springframework/cloud/context/named/NamedContextFactory.java

public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>        implements DisposableBean, ApplicationContextAware {    //......    protected AnnotationConfigApplicationContext getContext(String name) {        if (!this.contexts.containsKey(name)) {            synchronized (this.contexts) {                if (!this.contexts.containsKey(name)) {                    this.contexts.put(name, createContext(name));                }            }        }        return this.contexts.get(name);    }    protected AnnotationConfigApplicationContext createContext(String name) {        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();        if (this.configurations.containsKey(name)) {            for (Class<?> configuration : this.configurations.get(name)                    .getConfiguration()) {                context.register(configuration);            }        }        for (Map.Entry<String, C> entry : this.configurations.entrySet()) {            if (entry.getKey().startsWith("default.")) {                for (Class<?> configuration : entry.getValue().getConfiguration()) {                    context.register(configuration);                }            }        }        context.register(PropertyPlaceholderAutoConfiguration.class,                this.defaultConfigType);        context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(                this.propertySourceName,                Collections.<String, Object>singletonMap(this.propertyName, name)));        if (this.parent != null) {            // Uses Environment from parent as well as beans            context.setParent(this.parent);            // jdk11 issue            // https://github.com/spring-cloud/spring-cloud-netflix/issues/3101            context.setClassLoader(this.parent.getClassLoader());        }        context.setDisplayName(generateDisplayName(name));        context.refresh();        return context;    }    //......}        
  • NamedContextFactory的getContext主要是返回或者创建AnnotationConfigApplicationContext

小结

  • RibbonAutoConfiguration启用了RibbonEagerLoadProperties、ServerIntrospectorProperties两个配置,这里主要是注册了SpringClientFactory,创建LoadBalancerClient、LoadBalancedRetryFactory、RibbonApplicationContextInitializer、RestTemplateCustomizer及RibbonClientHttpRequestFactory
  • RibbonApplicationContextInitializer实现了ApplicationListener接口,其响应ApplicationReadyEvent事件执行initialize操作,这里主要是挨个对配置的clientNames执行springClientFactory.getContext(clientName)操作
  • SpringClientFactory的getContext方法调用了父类NamedContextFactory的getContext;NamedContextFactory的getContext主要是返回或者创建AnnotationConfigApplicationContext

doc

  • RibbonClientConfiguration