>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…

A. The preface

After looking at Dobbo’s registration process in previous articles, this stage will look at Dubbo’s discovery process

Dubbo’s findings include the following:

  • Scan and proxy for Reference
  • Reference Service Discovery
  • Load balancing
  • Service degradation

2. Obtaining Reference

Access to the entry

public DubboBootstrap start(a) {

	/ /.. Omit registration and container initialization
    
        // The starting point of the Reference scan is DubboBootstrap, which contains this code
        // Initiate Refer Services processing
	referServices();
    
	/ /...
     
}
Copy the code

2.1 Initialization Logic

private void referServices(a) {
    if (cache == null) {
        cache = ReferenceConfigCache.getCache();
    }
    // 
       -> 2.2 Obtain the list
    configManager.getReferences().forEach(rc -> {
        // TODO, compatible with ReferenceConfig.refer()ReferenceConfig<? > referenceConfig = (ReferenceConfig<? >) rc; referenceConfig.setBootstrap(this);
        if(! referenceConfig.isRefreshed()) { referenceConfig.refresh(); }if (rc.shouldInit()) {
            if (rc.shouldReferAsync()) {
                ExecutorService executor = executorRepository.getExportReferExecutor();
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        cache.get(rc);
                    } catch (Throwable t) {
                        logger.error("refer async catch error : " + t.getMessage(), t);
                    }
                }, executor);

                asyncReferringFutures.add(future);
            } else{ cache.get(rc); }}}); }Copy the code

2.2 References to manage

The list for

In 2.1, you can see the process of fetching from cache
configManager.getReferences()

publicCollection<ReferenceConfigBase<? >> getReferences() {return getConfigs(getTagName(ReferenceConfigBase.class));
}

Copy the code

The main principle is to get the Config prefix and then get the corresponding configuration information from a collection:

public static String getTagName(Class
        cls) {
    String tag = cls.getSimpleName();
    for (String suffix : SUFFIXES) {
        if (tag.endsWith(suffix)) {
            tag = tag.substring(0, tag.length() - suffix.length());
            break; }}return StringUtils.camelToSplitName(tag, "-");
}


final Map<String, Map<String, AbstractConfig>> configsCache = newMap();
// configType -> reference
private <C extends AbstractConfig> Map<String, C> getConfigsMap(String configType) {
    return (Map<String, C>) read(() -> configsCache.getOrDefault(configType, emptyMap()));
}

Copy the code

Take a look at that picture again:

3. Scan to generate Reference

3.1 Entrance of scanning

InitializingBean # afterPropertiesSet

C- ReferenceBean
public void afterPropertiesSet(a) throws Exception {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    
    // Get the BeanDefinition of the current Bean
    BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());
    this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
    this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
     
     // Get the Reference property
    if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {
        referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);
    } else {
        // omit attribute resolution for other diagrams
    }
        
        // Get the ReferenceBeanManager and initiate the registration logic
    ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
    referenceBeanManager.addReference(this);
}
Copy the code

3.2 RefenceBean Management entry

Let’s look at the flow of Reference

public void addReference(ReferenceBean referenceBean) throws Exception {

    String referenceBeanName = referenceBean.getId();
    PropertyResolver propertyResolver = applicationContext.getEnvironment();

    // Check whether the same object exists in the cache
    String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, propertyResolver);
    ReferenceBean oldReferenceBean = referenceIdMap.get(referenceBeanName);
    
    // Omit the oldRefence validation logic, which requires that if it exists in the cache, its application address should be consistent
    // PS: Because of the use of the! = The address of the comparison, avoiding the repetition of the Reference object
    
    referenceIdMap.put(referenceBeanName, referenceBean);
    // Save the cache and map the reference key to the referenceBename
    this.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);

    // If you add a reference after prepareReferenceBeans(), you should initialize it immediately
    if(initialized) { initReferenceBean(referenceBean); }}Copy the code

3.3 RefenceBean Initialization

private synchronized void  initReferenceBean(ReferenceBean referenceBean) throws Exception {

    if(referenceBean.getReferenceConfig() ! =null) {
        return;
    }

    // Build the referenceKey first
    String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext.getEnvironment());

    // Get the ReferenceConfig from the cache
    // PS: This is one of the two core classes of the second layer Config layer
    ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);
    if (referenceConfig == null) {
    
        // Create a real ReferenceConfig
        Map<String, Object> referenceAttributes = ReferenceBeanSupport.getReferenceAttributes(referenceBean);
        referenceConfig = ReferenceCreator.create(referenceAttributes, applicationContext)
                .defaultInterfaceClass(referenceBean.getObjectType())
                .build();

        // set id if it is not a generated name
        if(referenceBean.getId() ! =null && !referenceBean.getId().contains("#")) {
            referenceConfig.setId(referenceBean.getId());
        }

        // Step 1: cache: cache referenceConfig
        referenceConfigMap.put(referenceKey, referenceConfig);

        // Step 2: Register ReferenceConfig
        // core: call logic to add Config to collection
        DubboBootstrap.getInstance().reference(referenceConfig);
    }

    // Step 3: Associate referenceConfig to referenceBean
    referenceBean.setKeyAndReferenceConfig(referenceKey, referenceConfig);
}
Copy the code

3.4 Adding to a Collection

// C- DubboBootstrap
public DubboBootstrap reference(ReferenceConfig
        referenceConfig) {
    referenceConfig.setBootstrap(this);
    configManager.addReference(referenceConfig);
    return this;
}
Copy the code

Core addition process

// PS: check the logic, get the collection and add
protected <T extends AbstractConfig> T addConfig(AbstractConfig config, boolean unique) {
    return (T) write(() -> {
        Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> newMap());
        return addIfAbsent(config, configsMap, unique);
    });
}
Copy the code

3.5 ReferenceBeanManager supplement

ReferenceBeanManager properties

// Notice that ApplicationContextAware is implemented to notify the container
public class ReferenceBeanManager implements ApplicationContextAware {
    //reference bean id/name -> ReferenceBean
    private Map<String, ReferenceBean> referenceIdMap = new ConcurrentHashMap<>();

    //reference key -> [ reference bean names ]
    private Map<String, List<String>> referenceKeyMap = new ConcurrentHashMap<>();

    //reference key -> ReferenceConfig instance
    private Map<String, ReferenceConfig> referenceConfigMap = new ConcurrentHashMap<>();
    
    private ApplicationContext applicationContext;
    
}
Copy the code

supplement

3.3 Create ReferenceConfig process


referenceConfig = ReferenceCreator.create(referenceAttributes, applicationContext)
    .defaultInterfaceClass(referenceBean.getObjectType())
    .build();

// Step 1: Prepare the ReferenceCreator object
public static ReferenceCreator create(Map<String, Object> attributes, ApplicationContext applicationContext) {
    return new ReferenceCreator(attributes, applicationContext);
}

// Step 2: Create ReferenceConfig
public final ReferenceConfig build(a) throws Exception {
    ReferenceConfig configBean = new ReferenceConfig();
    // Core configuration
    configureBean(configBean);
    return configBean;

}

// Step 3: Core configuration process
protected void configureBean(ReferenceConfig configBean) throws Exception {
    populateBean(attributes, configBean);
    configureMonitorConfig(configBean);
    configureApplicationConfig(configBean);
    configureModuleConfig(configBean);
    configureConsumerConfig(attributes, configBean);
}

// if you don't know what you're doing, you're not doing it



Copy the code

Overall flow chart

ReferenceConfig data

<dubbo:reference id="demoService" />
Copy the code

conclusion

The more interesting thing about Reference is the deep use of Spring, which is worth studying in depth