在执行RibbonRoutingFilter#run()进行路由时会执行forward()方法,由于此处是在HystrixCommand内部执行Ribbon负载均衡调用,故使用ribbonCommandFactory创建RibbonCommand,Ribbon客户端的懒加载就在这个方法内,这里我们看HttpClientRibbonCommandFactory实现类
//## org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommandFactory public class HttpClientRibbonCommandFactory extends AbstractRibbonCommandFactory { @Override public HttpClientRibbonCommand create(final RibbonCommandContext context) { ZuulFallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId()); final String serviceId = context.getServiceId(); // 通过SpringClientFactory获取IClient接口实例 final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient( serviceId, RibbonLoadBalancingHttpClient.class); client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId)); return new HttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider, clientFactory.getClientConfig(serviceId)); } }创建RibbonLoadBalancingHttpClient的逻辑在 SpringClientFactory#getClient(serviceId, RibbonLoadBalancingHttpClient.class),如下:
SpringClientFactory#getInstance(name, clientClass)
NamedContextFactory#getInstance(name, type):
获取Client对应的ApplicationContext,如没有则调用createContext()创建,其中包含注册统一默认配置类RibbonClientConfiguration,或@RibbonClient、@RibbonClients(defaultConfiguration=xxx) 设置的配置类的逻辑
从ApplicationContext中根据类型获取实例,如没有使用反射创建,并通过IClientConfig配置
如上执行完毕RibbonClient就基本懒加载完成了,就可以到RibbonClient对应的ApplicationContext中继续获取其它核心接口的实现类了,这些实现类都是根据 默认/全局/Client自定义 配置创建的
//## org.springframework.cloud.netflix.ribbon.SpringClientFactory public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> { static final String NAMESPACE = "ribbon"; public SpringClientFactory() { super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name"); } /** * Get the rest client associated with the name. * @throws RuntimeException if any error occurs */ public <C extends IClient<?, ?>> C getClient(String name, Class<C> clientClass) { return getInstance(name, clientClass); } // name代表当前Ribbon客户端,type代表要获取的实例类型,如IClient、IRule @Override public <C> C getInstance(String name, Class<C> type) { // 先从父类NamedContextFactory中直接从客户端对应的ApplicationContext中获取实例 // 如果没有就根据IClientConfig中的配置找到具体的实现类,并通过反射初始化后放到Client对应的ApplicationContext中 C instance = super.getInstance(name, type); if (instance != null) { return instance; } IClientConfig config = getInstance(name, IClientConfig.class); return instantiateWithConfig(getContext(name), type, config); } // 使用IClientConfig实例化 static <C> C instantiateWithConfig(AnnotationConfigApplicationContext context, Class<C> clazz, IClientConfig config) { C result = null; try { // 通过以IClientConfig为参数的构造创建clazz类实例 Constructor<C> constructor = clazz.getConstructor(IClientConfig.class); result = constructor.newInstance(config); } catch (Throwable e) { // Ignored } // 如果没创建成功,使用无惨构造 if (result == null) { result = BeanUtils.instantiate(clazz); // 调用初始化配置方法 if (result instanceof IClientConfigAware) { ((IClientConfigAware) result).initWithNiwsConfig(config); } // 处理自动织入 if (context != null) { context.getAutowireCapableBeanFactory().autowireBean(result); } } return result; } } //## 父类 org.springframework.cloud.context.named.NamedContextFactory public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware { // 维护Ribbon客户端对应的ApplicationContext上下文 private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>(); // 维护Ribbon客户端的@Configuration配置类 private Map<String, C> configurations = new ConcurrentHashMap<>(); private ApplicationContext parent; private Class<?> defaultConfigType; // 默认配置类为 RibbonClientConfiguration private final String propertySourceName; // 默认为 ribbon private final String propertyName; // 默认读取RibbonClient名的属性为ribbon.client.name public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) { this.defaultConfigType = defaultConfigType; this.propertySourceName = propertySourceName; this.propertyName = propertyName; } // 如果包含Client上下文直接返回 // 如果不包含,调用createContext(name),并放入contexts集合 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); } // 创建名为name的RibbonClient的ApplicationContext上下文 protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); // configurations集合中是否包含当前Client相关配置类,包含即注入到ApplicationContext if (this.configurations.containsKey(name)) { for (Class<?> configuration : this.configurations.get(name) .getConfiguration()) { context.register(configuration); } } //configurations集合中是否包含default.开头的通过@RibbonClients(defaultConfiguration=xxx)配置的默认配置类 for (Map.Entry<String, C> entry : this.configurations.entrySet()) { if (entry.getKey().startsWith("default.")) { for (Class<?> configuration : entry.getValue().getConfiguration()) { context.register(configuration); } } } // 注册PropertyPlaceholderAutoConfiguration、RibbonClientConfiguration context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); // 添加 ribbon.client.name=具体RibbonClient name的enviroment配置 context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( this.propertySourceName, Collections.<String, Object> singletonMap(this.propertyName, name))); // 设置父ApplicationContext,这样可以使得当前创建的子ApplicationContext可以使用父上下文中的Bean if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); } context.refresh(); //刷新Context return context; } public <T> T getInstance(String name, Class<T> type) { AnnotationConfigApplicationContext context = getContext(name); if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) { return context.getBean(type); } return null; } }