dubbo spring初始化流程

125 阅读6分钟

spring中的初始化

在org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration中配置了各种初始化的方法。在DubboConfigurationProperties中有各种来自配置文件的config。比如:ApplicationConfig、ModuleConfig、RegistryConfig、ProtocolConfig、MonitorConfig、ProviderConfig、ConsumerConfig。他们在初始化的时候会把自己默认放到一个全局的ApplicationModel.getConfigManager()中。

    @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)  
    @Configuration  
    @AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)  
    @EnableConfigurationProperties(DubboConfigurationProperties.class)  
    @EnableDubboConfig  
    public class DubboAutoConfiguration implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {  
      
    /**  
    * Creates {@link ServiceClassPostProcessor} Bean  
    *  
    * @param packagesToScan the packages to scan  
    * @return {@link ServiceClassPostProcessor}  
    */  
    @ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)  
    @ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)  
    @ConditionalOnMissingBean  
    @Bean  
    public ServiceClassPostProcessor serviceClassPostProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)  
    Set<String> packagesToScan) {  
    return new ServiceClassPostProcessor(packagesToScan);  
    }  
      
    @Override  
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
    if (applicationContext instanceof ConfigurableApplicationContext) {  
    ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;  
    DubboLifecycleComponentApplicationListener dubboLifecycleComponentApplicationListener  
    = new DubboLifecycleComponentApplicationListener(applicationContext);  
    context.addApplicationListener(dubboLifecycleComponentApplicationListener);  
      // 主要是这里初始化相关功能
    DubboBootstrapApplicationListener dubboBootstrapApplicationListener = new DubboBootstrapApplicationListener(applicationContext);  
    context.addApplicationListener(dubboBootstrapApplicationListener);  
    }  
    }  
      
    @Override  
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {  
    // Remove the BeanDefinitions of ApplicationListener from DubboBeanUtils#registerCommonBeans(BeanDefinitionRegistry)  
    // TODO Refactoring in Dubbo 2.7.9  
    removeBeanDefinition(registry, DubboLifecycleComponentApplicationListener.BEAN_NAME);  
    removeBeanDefinition(registry, DubboBootstrapApplicationListener.BEAN_NAME);  
    }  
      
    private void removeBeanDefinition(BeanDefinitionRegistry registry, String beanName) {  
    if (registry.containsBeanDefinition(beanName)) {  
    registry.removeBeanDefinition(beanName);  
    }  
    }  
      
    @Override  
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {  
    // DO NOTHING  
    }  
    }

接下来去看DubboBootstrapApplicationListener类

    public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {  
      
    /**  
    * The bean name of {@link DubboBootstrapApplicationListener}  
    *  
    * @since 2.7.6  
    */  
    public static final String BEAN_NAME = "dubboBootstrapApplicationListener";  
      
    private final DubboBootstrap dubboBootstrap;  
      
    public DubboBootstrapApplicationListener() {  
    this.dubboBootstrap = DubboBootstrap.getInstance();  
    }  
      
    public DubboBootstrapApplicationListener(ApplicationContext applicationContext) {  
    super(applicationContext);  
    this.dubboBootstrap = DubboBootstrap.getInstance();  
    DubboBootstrapStartStopListenerSpringAdapter.applicationContext = applicationContext;  
    }  
      
    @Override  
    public void onApplicationContextEvent(ApplicationContextEvent event) {  
    if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {  
    DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();  
    }  
    if (event instanceof ContextRefreshedEvent) {  
    onContextRefreshedEvent((ContextRefreshedEvent) event);  
    } else if (event instanceof ContextClosedEvent) {  
    onContextClosedEvent((ContextClosedEvent) event);  
    }  
    }  
      
    private void onContextRefreshedEvent(ContextRefreshedEvent event) {  
    // 初始化dubbo相关的方法
    dubboBootstrap.start();  
    }  
      
    private void onContextClosedEvent(ContextClosedEvent event) {  
    DubboShutdownHook.getDubboShutdownHook().run();  
    }  
      
    @Override  
    public int getOrder() {  
    return LOWEST_PRECEDENCE;  
    }  
    }

接下来就是来自DubboBootstrap中的start全局初始化方法

public DubboBootstrap start() {  
if (started.compareAndSet(false, true)) {  
destroyed.set(false);  
ready.set(false);  
initialize();  
if (logger.isInfoEnabled()) {  
logger.info(NAME + " is starting...");  
}  
// 1. export Dubbo Services  
exportServices();  
  
// Not only provider register  
if (!isOnlyRegisterProvider() || hasExportedServices()) {  
// 2. export MetadataService  
exportMetadataService();  
//3. Register the local ServiceInstance if required  
registerServiceInstance();  
}  
  
referServices();  
if (asyncExportingFutures.size() > 0) {  
new Thread(() -> {  
try {  
this.awaitFinish();  
} catch (Exception e) {  
logger.warn(NAME + " exportAsync occurred an exception.");  
}  
ready.set(true);  
if (logger.isInfoEnabled()) {  
logger.info(NAME + " is ready.");  
}  
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);  
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));  
}).start();  
} else {  
ready.set(true);  
if (logger.isInfoEnabled()) {  
logger.info(NAME + " is ready.");  
}  
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);  
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));  
}  
if (logger.isInfoEnabled()) {  
logger.info(NAME + " has started.");  
}  
}  
return this;  
}

先看org.apache.dubbo.config.bootstrap.DubboBootstrap#initialize初始化方法

public void initialize() {  
if (!initialized.compareAndSet(false, true)) {  
return;  
}  
  
ApplicationModel.initFrameworkExts();  
  // 初始化配置中心
startConfigCenter();  
  // 初始化远程的配置
loadRemoteConfigs();  
  // 检查全局配置是不是异常
checkGlobalConfigs();  
  
// @since 2.7.8  寻找元数据
startMetadataCenter();  
  
 // 初始化元数据服务,和MetadataService这个接口相关的一些类
initMetadataService();  
  
if (logger.isInfoEnabled()) {  
logger.info(NAME + " has been initialized!");  
}  
}

看一下初始化配置中心的逻辑

private void startConfigCenter() {  
  
useRegistryAsConfigCenterIfNecessary();  
  //这里就是刚刚全局初始化的cm中获取的zk地址
Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();  
  
// check Config Center  
if (CollectionUtils.isEmpty(configCenters)) {  
ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();  
configCenterConfig.refresh();  
if (configCenterConfig.isValid()) {  
configManager.addConfigCenter(configCenterConfig);  
configCenters = configManager.getConfigCenters();  
}  
} else {  
for (ConfigCenterConfig configCenterConfig : configCenters) {  
// 这里的初始化就是给每一个字段去默认赋值
configCenterConfig.refresh();  
ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);  
}  
}  
  
if (CollectionUtils.isNotEmpty(configCenters)) {  
CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();  
for (ConfigCenterConfig configCenter : configCenters) {  
compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));  
}  
environment.setDynamicConfiguration(compositeDynamicConfiguration);  
}  
//这里把所有的config全部初始化了遍
configManager.refreshAll();  
}

接下来看一下初始化远程配置的

private void loadRemoteConfigs() {  
// registry ids to registry configs  
List<RegistryConfig> tmpRegistries = new ArrayList<>();  
// 获取远程的祖册配置
Set<String> registryIds = configManager.getRegistryIds();  
registryIds.forEach(id -> {  
if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {  
tmpRegistries.add(configManager.getRegistry(id).orElseGet(() -> {  
RegistryConfig registryConfig = new RegistryConfig();  
registryConfig.setId(id);  
registryConfig.refresh();  
return registryConfig;  
}));  
}  
});  
  // 添加远程的注册配置
configManager.addRegistries(tmpRegistries);  
  
// protocol ids to protocol configs  
List<ProtocolConfig> tmpProtocols = new ArrayList<>();  
Set<String> protocolIds = configManager.getProtocolIds();  
protocolIds.forEach(id -> {  
if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {  
tmpProtocols.add(configManager.getProtocol(id).orElseGet(() -> {  
ProtocolConfig protocolConfig = new ProtocolConfig();  
protocolConfig.setId(id);  
protocolConfig.refresh();  
return protocolConfig;  
}));  
}  
});  
  //添加远程协议
configManager.addProtocols(tmpProtocols);  
}

最后看一下检查配置

private void checkGlobalConfigs() {  
// 检查应用是不是为空
ConfigValidationUtils.validateApplicationConfig(getApplication());  
  
// 检查元数据是不是为空 
Collection<MetadataReportConfig> metadatas = configManager.getMetadataConfigs();  
if (CollectionUtils.isEmpty(metadatas)) {  
MetadataReportConfig metadataReportConfig = new MetadataReportConfig();  
metadataReportConfig.refresh();  
if (metadataReportConfig.isValid()) {  
configManager.addMetadataReport(metadataReportConfig);  
metadatas = configManager.getMetadataConfigs();  
}  
}  
if (CollectionUtils.isNotEmpty(metadatas)) {  
for (MetadataReportConfig metadataReportConfig : metadatas) {  
metadataReportConfig.refresh();  
ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);  
}  
}  
  
// 检查生产者是不是为空
Collection<ProviderConfig> providers = configManager.getProviders();  
if (CollectionUtils.isEmpty(providers)) {  
configManager.getDefaultProvider().orElseGet(() -> {  
ProviderConfig providerConfig = new ProviderConfig();  
configManager.addProvider(providerConfig);  
providerConfig.refresh();  
return providerConfig;  
});  
}  
for (ProviderConfig providerConfig : configManager.getProviders()) {  
ConfigValidationUtils.validateProviderConfig(providerConfig);  
}  
// 检查消费者是不是为空
Collection<ConsumerConfig> consumers = configManager.getConsumers();  
if (CollectionUtils.isEmpty(consumers)) {  
configManager.getDefaultConsumer().orElseGet(() -> {  
ConsumerConfig consumerConfig = new ConsumerConfig();  
configManager.addConsumer(consumerConfig);  
consumerConfig.refresh();  
return consumerConfig;  
});  
}  
for (ConsumerConfig consumerConfig : configManager.getConsumers()) {  
ConfigValidationUtils.validateConsumerConfig(consumerConfig);  
}  
  
// 检查监控是不是为空
ConfigValidationUtils.validateMonitorConfig(getMonitor());  
// 检查相关指标是不是为空
ConfigValidationUtils.validateMetricsConfig(getMetrics());  
// 检查模块是不是为空
ConfigValidationUtils.validateModuleConfig(getModule());  
// 检查ssl是不是为空 
ConfigValidationUtils.validateSslConfig(getSsl());  
}

接下来看start中的export方法

private void exportServices() {  
configManager.getServices().forEach(sc -> {  
// TODO, compatible with ServiceConfig.export()  
ServiceConfig serviceConfig = (ServiceConfig) sc;  
serviceConfig.setBootstrap(this);  

if (exportAsync) {  
ExecutorService executor = executorRepository.getServiceExporterExecutor();  
Future<?> future = executor.submit(() -> {  
try {  
exportService(serviceConfig);  
} catch (Throwable t) {  
logger.error("export async catch error : " + t.getMessage(), t);  
}  
});  
asyncExportingFutures.add(future);  
} else {  
exportService(serviceConfig);  
}  
});  
}

让我们直接深入内部最核心的方法 org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs, int protocolConfigNum) {  
// 省略点一堆获取配置的代码
...................................
 
if (ProtocolUtils.isGeneric(generic)) {  
map.put(GENERIC_KEY, generic);  
map.put(METHODS_KEY, ANY_VALUE);  
} else {  
String revision = Version.getVersion(interfaceClass, version);  
if (revision != null && revision.length() > 0) {  
map.put(REVISION_KEY, revision);  
}  
 
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();  
if (methods.length == 0) {  
logger.warn("No method found in service interface " + interfaceClass.getName());  
map.put(METHODS_KEY, ANY_VALUE);  
} else {  
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));  
}  
}  
 
/**  
* Here the token value configured by the provider is used to assign the value to ServiceConfig#token  
*/  
if (ConfigUtils.isEmpty(token) && provider != null) {  
token = provider.getToken();  
}  
 
if (!ConfigUtils.isEmpty(token)) {  
if (ConfigUtils.isDefault(token)) {  
map.put(TOKEN_KEY, UUID.randomUUID().toString());  
} else {  
map.put(TOKEN_KEY, token);  
}  
}  
//init serviceMetadata attachments  
serviceMetadata.getAttachments().putAll(map);  
 
// export service  
String host = findConfigedHosts(protocolConfig, registryURLs, map);  
Integer port = findConfigedPorts(protocolConfig, name, map, protocolConfigNum);  
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);  
 
// You can customize Configurator to append extra parameters  
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)  
.hasExtension(url.getProtocol())) {  
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)  
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);  
}  
 
String scope = url.getParameter(SCOPE_KEY);  
// don't export when none is configured  
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {  
 
// export to local if the config is not remote (export to remote only when config is remote)  
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {  
exportLocal(url);  
}  
// export to remote if the config is not local (export to local only when config is local)  
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {  
if (CollectionUtils.isNotEmpty(registryURLs)) {  
for (URL registryURL : registryURLs) {  
if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {  
url = url.addParameterIfAbsent(SERVICE_NAME_MAPPING_KEY, "true");  
}  
 
//if protocol is only injvm ,not register  
if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {  
continue;  
}  
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));  
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);  
if (monitorUrl != null) {  
url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());  
}  
if (logger.isInfoEnabled()) {  
if (url.getParameter(REGISTER_KEY, true)) {  
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " +  
registryURL);  
} else {  
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);  
}  
}  
 
// For providers, this is used to enable custom proxy to generate invoker  
String proxy = url.getParameter(PROXY_KEY);  
if (StringUtils.isNotEmpty(proxy)) {  
registryURL = registryURL.addParameter(PROXY_KEY, proxy);  
}  
 
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,  
registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));  
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);  
 
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);  
exporters.add(exporter);  
}  
} else {  
if (logger.isInfoEnabled()) {  
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);  
}  
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);  
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);  
 // 正常会来到这里去 去export。在这里会看你使用的那个协议
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);  
exporters.add(exporter);  
}  
 
MetadataUtils.publishServiceDefinition(url);  
}  
}  
this.urls.add(url);  
}

看一下dubbo协议中的export

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {  
URL url = invoker.getUrl();  
 
// export service.  
String key = serviceKey(url);  
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);  
exporterMap.addExportMap(key, exporter);  
 
//export an stub service for dispatching event  
Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);  
Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);  
if (isStubSupportEvent && !isCallbackservice) {  
String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);  
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {  
if (logger.isWarnEnabled()) {  
logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +  
"], has set stubproxy support event ,but no stub methods founded."));  
}  
 
}  
}  
 // 创建一个远程连接的方法开始等待消费者去调用。比如netty等
openServer(url);  
optimizeSerialization(url);  
 
return exporter;  
}

接下来回到org.apache.dubbo.config.bootstrap.DubboBootstrap#start去看一下referServices方案

private void referServices() {  
if (cache == null) {  
cache = ReferenceConfigCache.getCache();  
}  
  
configManager.getReferences().forEach(rc -> {  
// TODO, compatible with ReferenceConfig.refer()  
ReferenceConfig referenceConfig = (ReferenceConfig) rc;  
referenceConfig.setBootstrap(this);  
  
if (rc.shouldInit()) {  
if (referAsync) {  
CompletableFuture<Object> future = ScheduledCompletableFuture.submit(  
executorRepository.getServiceExporterExecutor(),  
() -> cache.get(rc)  
);  
asyncReferringFutures.add(future);  
} else {  
cache.get(rc);  
}  
}  
});  
}

接下来去看最核心的方法org.apache.dubbo.config.ReferenceConfig#init

public synchronized void init() {  
if (initialized) {  
return;  
}  
  
  
if (bootstrap == null) {  
bootstrap = DubboBootstrap.getInstance();  
// compatible with api call.  
if (null != this.getRegistries()) {  
bootstrap.registries(this.getRegistries());  
}  
bootstrap.initialize();  
}  
  
checkAndUpdateSubConfigs();  
  
checkStubAndLocal(interfaceClass);  
ConfigValidationUtils.checkMock(interfaceClass, this);  
  
Map<String, String> map = new HashMap<String, String>();  
map.put(SIDE_KEY, CONSUMER_SIDE);  
  
ReferenceConfigBase.appendRuntimeParameters(map);  
if (!ProtocolUtils.isGeneric(generic)) {  
String revision = Version.getVersion(interfaceClass, version);  
if (revision != null && revision.length() > 0) {  
map.put(REVISION_KEY, revision);  
}  
  
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();  
if (methods.length == 0) {  
logger.warn("No method found in service interface " + interfaceClass.getName());  
map.put(METHODS_KEY, ANY_VALUE);  
} else {  
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));  
}  
}  
map.put(INTERFACE_KEY, interfaceName);  
AbstractConfig.appendParameters(map, getMetrics());  
AbstractConfig.appendParameters(map, getApplication());  
AbstractConfig.appendParameters(map, getModule());  
// remove 'default.' prefix for configs from ConsumerConfig  
// appendParameters(map, consumer, Constants.DEFAULT_KEY);  
AbstractConfig.appendParameters(map, consumer);  
AbstractConfig.appendParameters(map, this);  
MetadataReportConfig metadataReportConfig = getMetadataReportConfig();  
if (metadataReportConfig != null && metadataReportConfig.isValid()) {  
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);  
}  
Map<String, AsyncMethodInfo> attributes = null;  
if (CollectionUtils.isNotEmpty(getMethods())) {  
attributes = new HashMap<>();  
for (MethodConfig methodConfig : getMethods()) {  
AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());  
String retryKey = methodConfig.getName() + ".retry";  
if (map.containsKey(retryKey)) {  
String retryValue = map.remove(retryKey);  
if ("false".equals(retryValue)) {  
map.put(methodConfig.getName() + ".retries", "0");  
}  
}  
AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);  
if (asyncMethodInfo != null) {  
// consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);  
attributes.put(methodConfig.getName(), asyncMethodInfo);  
}  
}  
}  
  
String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);  
if (StringUtils.isEmpty(hostToRegistry)) {  
hostToRegistry = NetUtils.getLocalHost();  
} else if (isInvalidLocalHost(hostToRegistry)) {  
throw new IllegalArgumentException(  
"Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);  
}  
map.put(REGISTER_IP_KEY, hostToRegistry);  
  
serviceMetadata.getAttachments().putAll(map);  
  
ref = createProxy(map);  
  
serviceMetadata.setTarget(ref);  
serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);  
ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey());  
consumerModel.setProxyObject(ref);  
consumerModel.init(attributes);  
  
initialized = true;  
  
checkInvokerAvailable();  
  
// dispatch a ReferenceConfigInitializedEvent since 2.7.4  
dispatch(new ReferenceConfigInitializedEvent(this, invoker));  
}public synchronized void init() {  
if (initialized) {  
return;  
}  
  
  
if (bootstrap == null) {  
bootstrap = DubboBootstrap.getInstance();  
// compatible with api call.  
if (null != this.getRegistries()) {  
bootstrap.registries(this.getRegistries());  
}  
bootstrap.initialize();  
}  
  
checkAndUpdateSubConfigs();  
  
checkStubAndLocal(interfaceClass);  
ConfigValidationUtils.checkMock(interfaceClass, this);  
  
Map<String, String> map = new HashMap<String, String>();  
map.put(SIDE_KEY, CONSUMER_SIDE);  
  
ReferenceConfigBase.appendRuntimeParameters(map);  
if (!ProtocolUtils.isGeneric(generic)) {  
String revision = Version.getVersion(interfaceClass, version);  
if (revision != null && revision.length() > 0) {  
map.put(REVISION_KEY, revision);  
}  
  
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();  
if (methods.length == 0) {  
logger.warn("No method found in service interface " + interfaceClass.getName());  
map.put(METHODS_KEY, ANY_VALUE);  
} else {  
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));  
}  
}  
map.put(INTERFACE_KEY, interfaceName);  
AbstractConfig.appendParameters(map, getMetrics());  
AbstractConfig.appendParameters(map, getApplication());  
AbstractConfig.appendParameters(map, getModule());  
// remove 'default.' prefix for configs from ConsumerConfig  
// appendParameters(map, consumer, Constants.DEFAULT_KEY);  
AbstractConfig.appendParameters(map, consumer);  
AbstractConfig.appendParameters(map, this);  
MetadataReportConfig metadataReportConfig = getMetadataReportConfig();  
if (metadataReportConfig != null && metadataReportConfig.isValid()) {  
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);  
}  
Map<String, AsyncMethodInfo> attributes = null;  
if (CollectionUtils.isNotEmpty(getMethods())) {  
attributes = new HashMap<>();  
for (MethodConfig methodConfig : getMethods()) {  
AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());  
String retryKey = methodConfig.getName() + ".retry";  
if (map.containsKey(retryKey)) {  
String retryValue = map.remove(retryKey);  
if ("false".equals(retryValue)) {  
map.put(methodConfig.getName() + ".retries", "0");  
}  
}  
AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);  
if (asyncMethodInfo != null) {  
// consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);  
attributes.put(methodConfig.getName(), asyncMethodInfo);  
}  
}  
}  
  
String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);  
if (StringUtils.isEmpty(hostToRegistry)) {  
hostToRegistry = NetUtils.getLocalHost();  
} else if (isInvalidLocalHost(hostToRegistry)) {  
throw new IllegalArgumentException(  
"Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);  
}  
map.put(REGISTER_IP_KEY, hostToRegistry);  
  
serviceMetadata.getAttachments().putAll(map);  
  // 最核心的方法还是要去看如何创建代码
ref = createProxy(map);  
  
serviceMetadata.setTarget(ref);  
serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);  
ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey());  
consumerModel.setProxyObject(ref);  
consumerModel.init(attributes);  
  
initialized = true;  
  
checkInvokerAvailable();  
  
// dispatch a ReferenceConfigInitializedEvent since 2.7.4  
dispatch(new ReferenceConfigInitializedEvent(this, invoker));  
}
private T createProxy(Map<String, String> map) {  
if (shouldJvmRefer(map)) {  
URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);  
invoker = REF_PROTOCOL.refer(interfaceClass, url);  
if (logger.isInfoEnabled()) {  
logger.info("Using injvm service " + interfaceClass.getName());  
}  
} else {  
urls.clear();  
if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.  
String[] us = SEMICOLON_SPLIT_PATTERN.split(url);  
if (us != null && us.length > 0) {  
for (String u : us) {  
URL url = URL.valueOf(u);  
if (StringUtils.isEmpty(url.getPath())) {  
url = url.setPath(interfaceName);  
}  
if (UrlUtils.isRegistry(url)) {  
urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));  
} else {  
urls.add(ClusterUtils.mergeUrl(url, map));  
}  
}  
}  
} else { // assemble URL from register center's configuration  
// if protocols not injvm checkRegistry  
if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {  
checkRegistry();  
List<URL> us = ConfigValidationUtils.loadRegistries(this, false);  
if (CollectionUtils.isNotEmpty(us)) {  
for (URL u : us) {  
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);  
if (monitorUrl != null) {  
map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));  
}  
urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));  
}  
}  
if (urls.isEmpty()) {  
throw new IllegalStateException(  
"No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() +  
" use dubbo version " + Version.getVersion() +  
", please config <dubbo:registry address=\"...\" /> to your spring config.");  
}  
}  
}  
  
if (urls.size() == 1) {  
invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));  
} else {  
List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();  
URL registryURL = null;  
for (URL url : urls) {  
// For multi-registry scenarios, it is not checked whether each referInvoker is available.  
// Because this invoker may become available later.  
// 在这里看一下如何通过协议去refer当前的使用
invokers.add(REF_PROTOCOL.refer(interfaceClass, url));  
  
if (UrlUtils.isRegistry(url)) {  
registryURL = url; // use last registry url  
}  
}  
  
if (registryURL != null) { // registry url is available  
// for multi-subscription scenario, use 'zone-aware' policy by default  
String cluster = registryURL.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);  
// The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker  
invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));  
} else { // not a registry url, must be direct invoke.  
String cluster = CollectionUtils.isNotEmpty(invokers)  
?  
(invokers.get(0).getUrl() != null ? invokers.get(0).getUrl().getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME) :  
Cluster.DEFAULT)  
: Cluster.DEFAULT;  
invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));  
}  
}  
}  
  
if (logger.isInfoEnabled()) {  
logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());  
}  
  
URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);  
MetadataUtils.publishServiceDefinition(consumerURL);  
  
// create service proxy  
return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));  
}

来看一下dubbo协议中的org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#protocolBindingRefer

public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {  
optimizeSerialization(url);  
  
// 在这里创建了一个invoker来实现远程调用  
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);  
invokers.add(invoker);  
  
return invoker;  
}