Ribbon服务实现不同服务,不同配置是通过@RibbonClient
和RibbonClients
两个注解来实现的。@RibbonClient
注册的某个Client配置类。@RibbonClients
注册的全局默认配置类。
Feign实现不同服务,不同配置,是根据FeignClient
来获取自定义的配置。
示例
定义Ribbon配置类
public class AppRibbonConfig {
@Bean
public IPing iping() {
return new DummyPing();
}
}
启动类上添加注解
@RibbonClient(name = "app-provider", configuration = AppRibbonConfig.class)
源码解析
@RibbonClient
和@RibbonClients
这两个注解的功能都是引入RibbonClientConfigurationRegistrar
,该类主要是生成RibbonClientSpecification
的BeanDefinition。
RibbonAutoConfiguration
该类会获取到所有的RibbonClientSpecification
,设置到SpringClientFactory
的map集合中。
public class RibbonAutoConfiguration {
@Autowired(
required = false
)
private List<RibbonClientSpecification> configurations = new ArrayList();
@Autowired
private RibbonEagerLoadProperties ribbonEagerLoadProperties;
public RibbonAutoConfiguration() {
}
@Bean
public HasFeatures ribbonFeature() {
return HasFeatures.namedFeature("Ribbon", Ribbon.class);
}
@Bean
public SpringClientFactory springClientFactory() {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
}
系统中默认的配置有RibbonAutoConfiguration
和RibbonEurekaAutoConfiguration
,RibbonEurekaAutoConfiguration
类上的注解上含有配置类,EurekaRibbonClientConfiguration
。
@Configuration
@EnableConfigurationProperties
@ConditionalOnRibbonAndEurekaEnabled
@AutoConfigureAfter({RibbonAutoConfiguration.class})
@RibbonClients(
defaultConfiguration = {EurekaRibbonClientConfiguration.class}
)
public class RibbonEurekaAutoConfiguration {
public RibbonEurekaAutoConfiguration() {
}
}
@EnableFeignClients
该类会注册FeignClientSpecification
。FeignClientsRegistrar#registerBeanDefinitions
,会加载默认配置和对应的FeignClient
服务名的配置。
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
this.registerDefaultConfiguration(metadata, registry);
this.registerFeignClients(metadata, registry);
}
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
} else {
name = "default." + metadata.getClassName();
}
this.registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
}
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
}
FeignAutoConfiguration
FeignAutoConfiguration
会获取到FeignClientSpecification
@Configuration
@ConditionalOnClass({Feign.class})
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
@Autowired(
required = false
)
private List<FeignClientSpecification> configurations = new ArrayList();
public FeignAutoConfiguration() {
}
@Bean
public HasFeatures feignFeature() {
return HasFeatures.namedFeature("Feign", Feign.class);
}
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
FeignClientFactoryBean
系统启动的时候,会加载FeignClientFactoryBean
,会执行FeignClientFactoryBean#getObject
,获取到context对象,从而获取相应的组件。
protected Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = (FeignLoggerFactory)this.get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
Builder builder = ((Builder)this.get(context, Builder.class)).logger(logger).encoder((Encoder)this.get(context, Encoder.class)).decoder((Decoder)this.get(context, Decoder.class)).contract((Contract)this.get(context, Contract.class));
this.configureFeign(context, builder);
return builder;
}
protected <T> T get(FeignContext context, Class<T> type) {
T instance = context.getInstance(this.contextId, type);
if (instance == null) {
throw new IllegalStateException("No bean found of type " + type + " for " + this.contextId);
} else {
return instance;
}
}
第一次访问服务
Ribbon是懒加载的,NamedContextFactory#getContext
,第一次访问是没有context对象的,所以会进行创建。
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized(this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, this.createContext(name));
}
}
}
return (AnnotationConfigApplicationContext)this.contexts.get(name);
}
NamedContextFactory#createContext
,根据服务配置生成对应的AnnotationConfigApplicationContext
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (this.configurations.containsKey(name)) {
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});
}
}
Iterator var9 = this.configurations.entrySet().iterator();
while(true) {
Entry entry;
do {
if (!var9.hasNext()) {
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));
context.refresh();
return context;
}
entry = (Entry)var9.next();
} while(!((String)entry.getKey()).startsWith("default."));
Class[] var11 = ((NamedContextFactory.Specification)entry.getValue()).getConfiguration();
int var12 = var11.length;
for(int var7 = 0; var7 < var12; ++var7) {
Class<?> configuration = var11[var7];
context.register(new Class[]{configuration});
}
}
}
Ribbon提前加载
ribbon:
eager-load:
clients: app-provider
enabled: true
在RibbonAutoConfiguration
中会根据配置判断是否生成对象ribbonApplicationContextInitializer
@Bean
@ConditionalOnProperty({"ribbon.eager-load.enabled"})
public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {
return new RibbonApplicationContextInitializer(this.springClientFactory(), this.ribbonEagerLoadProperties.getClients());
}
RibbonApplicationContextInitializer#initialize
,该类主要是根据配置的clients数据对相应的服务进行加载
protected void initialize() {
if (this.clientNames != null) {
Iterator var1 = this.clientNames.iterator();
while(var1.hasNext()) {
String clientName = (String)var1.next();
this.springClientFactory.getContext(clientName);
}
}
}