Dubbo Learning Record (9) - Analyse du code source du processus de détermination des paramètres de service pour l'exportation de services

Exportation du service Dubbo

Système de difficulté : ⭐⭐⭐⭐⭐

Pour l'exportation du service Dubbo, appelez ServiceBean#export(), puis appelez la méthode ServiceConfig#export() de la classe parente pour exporter réellement le service ;

Processus général d'exportation du service Dubbo

  1. Chaque annotation Service de Dubbo correspond à un objet ServiceBean. Chaque objet ServiceBean implémente l'interface Spring ApplicationListener. Lorsque le projet Spring est démarré, un événement d'actualisation de contexte ContextRefreshEvent sera déclenché. La méthode de déclenchement est la méthode onApplicationEvent, ServiceBean onApplicationEvent Dans la méthode , ServiceBean#export() sera appelé, puis la méthode de la classe parente ServiceConfig#export() sera appelée pour exporter le service
  2. Il déterminera les paramètres de configuration de chaque ServiceBean, tels que le délai d'attente, le protocole, etc. La configuration de ces paramètres peut être configurée aux endroits suivants :
    2.1 Paramètres de fonctionnement de l'environnement JVM, spécifiez les paramètres par -D
    2.2 Le centre de configuration du projet Et la configuration de l'application, qui équivaut à un fichier Dubbo.properties partagé distribué ;
    2.3 L'annotation @Service peut spécifier des paramètres ;
    2.4 Dans le projet, le fichier de configuration dubbo.properties spécifié ;
    tant d'endroits peuvent spécifier des paramètres de configuration, lorsque le service est exporté, Il est nécessaire de déterminer quels paramètres de configuration sont utilisés par chaque Service, c'est-à-dire de déterminer les paramètres les plus prioritaires ;
  3. Charger et déterminer les informations du centre d'enregistrement ;
  4. Démarrez le conteneur selon le protocole configuré, le protocole Dubbo correspond à Netty, http correspond à tomcat/jetty, et dans le processus de réception des requêtes, recevez les requêtes selon notre configuration, telles que les événements de délai d'attente, le nombre maximum de connexions, etc. ;
  5. Une fois le conteneur démarré, la configuration de service de chaque ServiceBean sera enregistrée auprès du centre d'enregistrement et, en même temps, il s'enregistrera pour surveiller la configuration du service et surveiller les modifications de configuration ;

Il s'agit principalement de ces processus, il est plus simple de déterminer les paramètres de configuration du service => démarrer le conteneur => s'inscrire au centre d'enregistrement ;

notion de service

  1. Dans l'appel traditionnel à trois niveaux, l'interface de service est la définition du service et le ServiceImpl est l'implémentation spécifique du service ; il en va de même pour dubbo ;
  2. Interface de service + groupe groupe + numéro de version version définit un service plus en détail ;
  3. interface ip:port/service : accéder à distance à un service via le numéro de port IP ;
  4. ip:port/service interface?group =xxx & version=xxx & timeout=xxx & … : spécifiez le serveur distant via le port IP, définissez un service plus en détail via l'interface de service + les paramètres de configuration de l'interface, et déterminez l'unicité de le service;

comme:

127.0.0.1:8080/com.dubbo.demo.DemoService?group=user&version=1.0&timout=5000&applicationName=demo

Dubbo utilise le quatrième type pour définir de manière unique un service Service ;

Récapitulatif du processus de code d'exportation de service

  1. Charger les paramètres de configuration du service identifié ;
  2. Chargez les informations de l'URL du centre d'enregistrement ;
  3. Construire l'URL finale du service ;
  4. Configurez Protocolcol pour démarrer différents conteneurs selon le protocole de réception des requêtes ;
  5. L'URL du service est enregistrée dans le centre d'enregistrement ;
  6. Surveillez les informations de configuration du service, si la configuration change, réexportez le service ;

Charger les paramètres de configuration qui déterminent le service

  • Chaque @Service correspond à une instance de configuration de service ServiceBean, et pendant le processus de démarrage du service, lorsque l'annotation @DubboComponentScan est exécutée, chaque @Service sera converti en une instance ServiceBean un par un, et les informations de configuration dans l'annotation @Service seront être affecté à l'instance ServiceBean, y compris certaines valeurs communes timeout, et certaines configurations Dubbo, telles que protocolConfig, etc. ;
  • Dans Dubbo, en plus de configurer les paramètres du service dans l'annotation @Service, il existe de nombreux endroits où vous pouvez également configurer les paramètres du service
  1. Fichier de ressources de ressources dubbo.properties : Dubbo analysera ces fichiers de configuration et les chargera en tant que PropertiesConfiguration ;
  2. Centre de configuration : un fichier de propriétés distribué, comprenant deux types, l'un est la configuration globale et l'autre est la configuration de l'application ; dans le code source de Dubbo, AppExternalConfiguration signifie la configuration de l'application et ExternalConfiguration signifie la configuration globale.
  3. Annotation @Service : AbstractConfig correspondant ;
  4. Paramètres d'environnement JVM : exécutez la configuration via -D, et la classe correspondante est SystemConfiguration ;
  • Si le même paramètre est configuré à ces endroits en même temps, la priorité de haut en bas est :
    SystemConfig > AppExternalConfiguration > ExternalConfiguration > AbstractConfig > PropertiesConfiguration,
    c'est-à-dire que le paramètre configuré en mode -D a la priorité la plus élevée, suivi de la centre de configuration, suivi de l'annotation, dubbo.properties last.

  • Étant donné que les paramètres de configuration peuvent être configurés à plusieurs endroits en même temps, la première étape de l'exportation d'un service consiste à déterminer les paramètres de configuration du service ;

ServiceConfig#export()

    public synchronized void export() {
    
    
        //确定配置参数
        checkAndUpdateSubConfigs();
		//...省略部分代码
            // 导出服务
            doExport();
        }
    }

ServiceConfig#checkAndUpdateSubConfigs()

Travail:

  1. paramètres de configuration d'achèvement completeCompoundConfigs
  2. Obtenir la configuration de l'application et la configuration globale à partir du centre de configuration
  3. Obtenez l'objet ProviderConfig ;
  4. Obtenez l'objet de protocole Protocol, la valeur par défaut est le protocole Dubbo ;
  5. Obtenez l'objet ApplicationConfig ;
  6. Obtenir la configuration du service de registre ;
  7. Mettez à jour le paramètre ServiceConfig sur la configuration avec la priorité la plus élevée ;
  8. Vérifier si le service actuel est un service généralisé
  9. Chèque Stub et Local
  10. Vérifier la simulation

    public void checkAndUpdateSubConfigs() {
    
    

        completeCompoundConfigs();

        // Config Center should always being started first.
        // 从配置中心获取配置,包括应用配置和全局配置
        // 把获取到的配置放入到Environment中的externalConfigurationMap和appExternalConfigurationMap中
        // 并刷新所有的Config属性
        startConfigCenter();

        // 如果没有ProviderConfig对象,则创建一个
        checkDefault();

        // 如果没有单独的配置protocols,那么就从provider获取配置的协议,添加到的ServiceConfig中去
        // 假如程序员在配置文件中配了一个dubbo协议,配置中心的全局配置或应用配置中也配置了一个协议,那么就会被添加到ServiceConfig中
        checkProtocol();


        checkApplication();


        // if protocol is not injvm checkRegistry
        // 如果protocol不是只有injvm协议,表示服务调用不是只在本机jvm里面调用,那就需要用到注册中心
        // 如果protocol是injvm,表示本地调用
        if (!isOnlyInJvm()) {
    
    
            checkRegistry();
        }

        // 刷新ServiceConfig
        this.refresh();

        // 如果配了metadataReportConfig,那么就刷新配置
        checkMetadataReport();

        if (StringUtils.isEmpty(interfaceName)) {
    
    
            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
        }

        // 当前服务对应的实现类是一个GenericService,表示没有特定的接口
        if (ref instanceof GenericService) {
    
    
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
    
    
                generic = Boolean.TRUE.toString();
            }
        } else {
    
    
            // 加载接口
            try {
    
    
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
    
    
                throw new IllegalStateException(e.getMessage(), e);
            }
            // 刷新MethodConfig,并判断MethodConfig中对应的方法在接口中是否存在
            checkInterfaceAndMethods(interfaceClass, methods);
            // 实现类是不是该接口类型
            checkRef();
            generic = Boolean.FALSE.toString();
        }
        // local和stub一样,不建议使用了
        if (local != null) {
    
    
            // 如果本地存根为true,则存根类为interfaceName + "Local"
            if (Boolean.TRUE.toString().equals(local)) {
    
    
                local = interfaceName + "Local";
            }
            // 加载本地存根类
            Class<?> localClass;
            try {
    
    
                localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
            } catch (ClassNotFoundException e) {
    
    
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(localClass)) {
    
    
                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
        // 本地存根
        if (stub != null) {
    
    
            // 如果本地存根为true,则存根类为interfaceName + "Stub"
            if (Boolean.TRUE.toString().equals(stub)) {
    
    
                stub = interfaceName + "Stub";
            }
            Class<?> stubClass;
            try {
    
    
                stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
    
    
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(stubClass)) {
    
    
                throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
        // 检查local和stub
        checkStubAndLocal(interfaceClass);
        // 检查mock
        checkMock(interfaceClass);
    }

ServiceConfig#completeCompoundConfigs()'

  1. Le fournisseur est configuré, mais l'application, le module, les registres, le moniteur, les protocoles, configCenter ne sont pas configurés, et ces configurations sont obtenues auprès du fournisseur ;
  2. Le module est configuré, mais les registres et configCenter ne sont pas configurés, et ces configurations sont obtenues à partir du module ;
  3. L'application est configurée, mais les registres et le moniteur ne sont pas configurés, et ces configurations sont obtenues à partir de l'application ;
 private void completeCompoundConfigs() {
    
    
        // 如果配置了provider,那么则从provider中获取信息赋值其他属性,在这些属性为空的情况下
        if (provider != null) {
    
    
            if (application == null) {
    
    
                setApplication(provider.getApplication());
            }
            if (module == null) {
    
    
                setModule(provider.getModule());
            }
            if (registries == null) {
    
    
                setRegistries(provider.getRegistries());
            }
            if (monitor == null) {
    
    
                setMonitor(provider.getMonitor());
            }
            if (protocols == null) {
    
    
                setProtocols(provider.getProtocols());
            }
            if (configCenter == null) {
    
    
                setConfigCenter(provider.getConfigCenter());
            }
        }
        // 如果配置了module,那么则从module中获取信息赋值其他属性,在这些属性为空的情况下
        if (module != null) {
    
    
            if (registries == null) {
    
    
                setRegistries(module.getRegistries());
            }
            if (monitor == null) {
    
    
                setMonitor(module.getMonitor());
            }
        }
        // 如果配置了application,那么则从application中获取信息赋值其他属性,在这些属性为空的情况下
        if (application != null) {
    
    
            if (registries == null) {
    
    
                setRegistries(application.getRegistries());
            }
            if (monitor == null) {
    
    
                setMonitor(application.getMonitor());
            }
        }
    }

ServiceConfig#startConfigCenter()

  1. Configurez configCenter pour obtenir des informations d'attribut pertinentes du centre de configuration à partir d'autres emplacements, tels que l'adresse du centre de configuration
  2. Après avoir mis à jour les propriétés, obtenez la configuration globale à partir de la configuration et appliquez la configuration ;
  3. Après avoir obtenu la configuration, actualisez toutes les propriétés XXXconfig ;
    void startConfigCenter() {
    
    
        if (configCenter == null) {
    
    
            ConfigManager.getInstance().getConfigCenter().ifPresent(cc -> this.configCenter = cc);
        }

        // 如果配置了ConfigCenter
        if (this.configCenter != null) {
    
    

           
            // TODO there may have duplicate refresh
            this.configCenter.refresh();

            // 属性更新后,从远程配置中心获取数据(应用配置,全局配置)
            prepareEnvironment();
        }

        // 从配置中心取到配置数据后,刷新所有的XxConfig中的属性
        ConfigManager.getInstance().refreshAll();
    }
ServiceConfig#refresh

Travail:

  1. Obtenez toutes les configurations de dubbo pertinentes ;
  2. Créez un objet Configuration représentant AbstractConfig ;
  3. La valeur de isConfigCenterFirst est true par défaut, donc l'ordre de priorité est : variable système -> configuration de l'application du centre de configuration -> configuration globale du centre de configuration -> annotation ou définition dans xml -> fichier dubbo.properties ;
  4. Utilisez la technologie de réflexion pour attribuer la valeur de la configuration la plus prioritaire ;
public void refresh() {
    
    
        try {
    
    
            CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());

            // 表示XxConfig对象本身- AbstractConfig
            Configuration config = new ConfigConfigurationAdapter(this);

            if (Environment.getInstance().isConfigCenterFirst()) {
    
    
                // The sequence would be: SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
                compositeConfiguration.addConfiguration(4, config);
            } else {
    
    
                // The sequence would be: SystemConfiguration -> AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> PropertiesConfiguration
                compositeConfiguration.addConfiguration(2, config);
            }

            // loop methods, get override value and set the new value back to method
            //
            Method[] methods = getClass().getMethods();
            for (Method method : methods) {
    
    
                // 是不是setXX()方法
                if (MethodUtils.isSetter(method)) {
    
    
                    // 获取xx配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
                    if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
    
    
                        method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
                    }
                  // 是不是setParameters()方法
                } else if (isParametersSetter(method)) {
    
    
                    // 获取parameter配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    if (StringUtils.isNotEmpty(value)) {
    
    
                        Map<String, String> map = invokeGetParameters(getClass(), this);
                        map = map == null ? new HashMap<>() : map;
                        map.putAll(convert(StringUtils.parseParameters(value), ""));
                        invokeSetParameters(getClass(), this, map);
                    }
                }
            }
        } catch (Exception e) {
    
    
            logger.error("Failed to override ", e);
        }
    }
La configuration du centre de configuration détermine la priorité
Environnement.getInstance().getConfiguration(getPrefix(), getId())

getInstance() : style chinois avide de singleton ;

public class Environment {
    
    
	//存放各种配置;
    private Map<String, PropertiesConfiguration> propertiesConfigs = new ConcurrentHashMap<>();
    private Map<String, SystemConfiguration> systemConfigs = new ConcurrentHashMap<>();
    private Map<String, EnvironmentConfiguration> environmentConfigs = new ConcurrentHashMap<>();
    private Map<String, InmemoryConfiguration> externalConfigs = new ConcurrentHashMap<>();
    private Map<String, InmemoryConfiguration> appExternalConfigs = new ConcurrentHashMap<>();

    private static final Environment INSTANCE = new Environment();
    public static Environment getInstance() {
    
    
        return INSTANCE;
    }
}

getConfiguration : obtenez la configuration et placez-la dans le conteneur List à l'intérieur de CompositeConfiguration ;

  1. Variables d'environnement JVM
  2. Variables d'environnement du système d'exploitation (je n'ai pas touché)
  3. Configuration de l'application du centre de configuration
  4. Configuration globale globale du centre de configuration
  5. Configuration dans dubbo.properties
  6. Renvoie l'instance de compositeConfiguration ;

On peut voir qu'ils sont obtenus séparément, et la priorité peut être initialement connue dans l'ordre.
Variables de configuration système > centre de configuration > configuration du fichier dubbo ;

    public CompositeConfiguration getConfiguration(String prefix, String id) {
    
    
        CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
        // Config center has the highest priority

        // JVM环境变量
        compositeConfiguration.addConfiguration(this.getSystemConfig(prefix, id));
        // 操作系统环境变量
        compositeConfiguration.addConfiguration(this.getEnvironmentConfig(prefix, id));

        // 配置中心APP配置
        compositeConfiguration.addConfiguration(this.getAppExternalConfig(prefix, id));

        // 配置中心Global配置
        compositeConfiguration.addConfiguration(this.getExternalConfig(prefix, id));

        // dubbo.properties中的配置
        compositeConfiguration.addConfiguration(this.getPropertiesConfig(prefix, id));
        return compositeConfiguration;
    }

Classe CompositeConfiguration : il y a une collection List à l'intérieur pour stocker la configuration ;

public class CompositeConfiguration implements Configuration {
    
    
    /**
     * List holding all the configuration
     */
    private List<Configuration> configList = new LinkedList<Configuration>();
}
Environnement.getInstance().isConfigCenterFirst()

On peut savoir que : Par défaut, la valeur de configCenterFirst est true ;

public class Environment {
    
    
    private static final Environment INSTANCE = new Environment();
    private boolean configCenterFirst = true;
    public boolean isConfigCenterFirst() {
    
    
        return configCenterFirst;
    }
  }  

Par conséquent, dans le code suivant, insérez la configuration représentant AbstractConfig dans la quatrième position de la collection ;

    public void refresh() {
    
    
        try {
    
    
            CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());

            // 表示XxConfig对象本身- AbstractConfig
            Configuration config = new ConfigConfigurationAdapter(this);

            if (Environment.getInstance().isConfigCenterFirst()) {
    
    
                compositeConfiguration.addConfiguration(4, config);
            } else {
    
    
                compositeConfiguration.addConfiguration(2, config);
            }
	//...
}

La priorité de la configuration finale est : Variables de configuration système > Centre de configuration > Configuration d'annotation @Service > configuration du fichier dubbo ;

La configuration du centre de configuration attribue la valeur de priorité la plus élevée
  1. Obtenir toutes les méthodes de la classe de configuration ServiceConfig
  2. Méthode de traversée
  3. Déterminez s'il s'agit d'une méthode de setter ;

  4. S'il s'agit d'une méthode setter, utilisez compositeConfiguration.getString( extractPropertyName (getClass(), method) pour obtenir la valeur de la propriété
    . est inclus, cela signifie qu'il est trouvé en premier La configuration de plus haut niveau, return;
  5. affectation par réflexion ;
  6. S'il ne s'agit pas d'une méthode setter, il s'agit d'une méthode setParameters ;
  7. Obtenez la valeur de l'élément de configuration de paramètre ;
  8. Obtenez la valeur du paramètre en appelant la méthode getParameters par réflexion ;
  9. Fusionnez la valeur du paramètre et attribuez la valeur en appelant la méthode setParameter par réflexion ;
   public void refresh() {
    
    
        try {
    
    
			//...省略确定优先级别的代码
            Method[] methods = getClass().getMethods();
            for (Method method : methods) {
    
    
                // 是不是setXX()方法
                if (MethodUtils.isSetter(method)) {
    
    
                    // 获取xx配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
                    if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
    
    
                        method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
                    }
                  // 是不是setParameters()方法
                } else if (isParametersSetter(method)) {
    
    
                    // 获取parameter配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    if (StringUtils.isNotEmpty(value)) {
    
    
                        Map<String, String> map = invokeGetParameters(getClass(), this);
                        map = map == null ? new HashMap<>() : map;
                        map.putAll(convert(StringUtils.parseParameters(value), ""));
                        invokeSetParameters(getClass(), this, map);
                    }
                }
            }
        } catch (Exception e) {
    
    
        //...
        }
    }
prepareEnvironment()

Objectif : obtenir la configuration du centre de configuration ;

  1. Obtenir un centre de configuration dynamique ;
  2. Obtenez le contenu configContent de la configuration globale ;
  3. Obtenez le nom du groupe de gestion ;
  4. S'il existe un groupe de gestion, il existe une configuration d'application App et le contenu appConfigContent de la configuration d'application est obtenu ;
  5. Définissez la valeur de la propriété configCenterFirst sur true ;
  6. Analysez le contenu de la configuration globale et attribuez-le à Environment#externalConfigurationMap ;
  7. Analysez le contenu de la configuration de l'application et attribuez-le à Environment#appExternalConfigurationMap
private void prepareEnvironment() {
    
    
        if (configCenter.isValid()) {
    
    
            if (!configCenter.checkOrUpdateInited()) {
    
    
                return;
            }

            // 动态配置中心,管理台上的配置中心
            DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());

            // 如果是zookeeper,获取的就是/dubbo/config/dubbo/dubbo.properties节点中的内容
            String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());

            String appGroup = application != null ? application.getName() : null;
            String appConfigContent = null;
            if (StringUtils.isNotEmpty(appGroup)) {
    
    
                // 获取的就是/dubbo/config/dubbo-demo-consumer-application/dubbo.properties节点中的内容
                // 这里有bug
                appConfigContent = dynamicConfiguration.getProperties
                        (StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
                         appGroup
                        );
            }
            try {
    
    
                Environment.getInstance().setConfigCenterFirst(configCenter.isHighestPriority());
                Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent));
                Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent));
            } catch (IOException e) {
    
    
                throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
            }
        }
    }
ConfigManager.getInstance().refreshAll()

Les étapes ci-dessus actualisent uniquement la dernière valeur de ConfigCenterConfig ; alors que les valeurs des autres classes de configuration telles que ApplicationConfig, ProtocolConfig, etc. ne sont pas la valeur de priorité la plus élevée, ces classes de configuration doivent également être actualisées et recevoir la valeur de priorité la plus élevée ;

    public void refreshAll() {
    
    
        // refresh all configs here,
        getApplication().ifPresent(ApplicationConfig::refresh);
        getMonitor().ifPresent(MonitorConfig::refresh);
        getModule().ifPresent(ModuleConfig::refresh);

        getProtocols().values().forEach(ProtocolConfig::refresh);
        getRegistries().values().forEach(RegistryConfig::refresh);
        getProviders().values().forEach(ProviderConfig::refresh);
        getConsumers().values().forEach(ConsumerConfig::refresh);
    }

Le code est très bien écrit, en utilisant la réflexion, donc la polyvalence est très élevée ;
le processus est similaire à ConfigCenterConfig, et il n'est pas nécessaire de répéter le code.

ServiceConfig#checkDefault()

Objectif : S'il n'y a pas d'objet ProviderConfig, créez-en un

    private void checkDefault() {
    
    
        createProviderIfAbsent();
    }
    private void createProviderIfAbsent() {
    
    
        if (provider != null) {
    
    
            return;
        }
        setProvider(
                ConfigManager.getInstance()
                        .getDefaultProvider()
                        .orElseGet(() -> {
    
    
                        	//创建ProviderConfig实例,并赋最高优先级别的值;
                            ProviderConfig providerConfig = new ProviderConfig();
                            providerConfig.refresh();
                            return providerConfig;
                        })
        );
    }
    //给配置管理器设置Provider;
    public void setProvider(ProviderConfig provider) {
    
    
        ConfigManager.getInstance().addProvider(provider);
        this.provider = provider;
    }   

ServiceConfig#checkProtocol

Objectif : obtenir les paramètres ProtocolConfig ;
travail :

  1. S'il n'y a pas de protocoles de configuration distincts, obtenez le protocole configuré auprès du fournisseur et ajoutez-le au ServiceConfig
  2. Si le programmeur configure un protocole dubbo dans le fichier de configuration, et configure un protocole dans la configuration globale ou la configuration applicative du centre de configuration, il sera ajouté à ServiceConfig. 2.1 Obtenir le protocole
    de la configuration globale, selon le préfixe « dubbo .protocols. " Obtenu à partir de externalConfigurationMap ;
    2.2 Obtenir le protocole de la configuration de l'application, et l'obtenir à partir de appExternalConfigurationMap selon le préfixe "dubbo.protocols." ;
    2.3 Splicing configuration ;
    2.4 S'il n'y a pas de configuration dans le centre de configuration, utilisez le configuration par défaut du protocole Dubbo pour créer un ProtocolConfig par défaut Attribuez des valeurs à ConfigManager pour la gestion ;
    2.5 S'il existe des configurations dans le centre de configuration, créez un ProtocolConfig pour chaque configuration, puis remettez-les à ConfigManager pour la gestion ;
private void checkProtocol() {
    
    
		//如果没有单独的配置protocols,那么就从provider获取配置的协议,添加到的ServiceConfig中去
        if (CollectionUtils.isEmpty(protocols) && provider != null) {
    
    
            setProtocols(provider.getProtocols());
        }
        convertProtocolIdsToProtocols();
    }

    private void convertProtocolIdsToProtocols() {
    
    

        if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) {
    
    
            List<String> configedProtocols = new ArrayList<>();

            // 从配置中心的全局配置获取dubbo.protocols.的配置项值
            configedProtocols.addAll(getSubProperties(Environment.getInstance()
                    .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));

            // 从配置中心的应用配置获取dubbo.protocols.的配置项值
            configedProtocols.addAll(getSubProperties(Environment.getInstance()
                    .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));

            // 用,号join所有的protocol
            protocolIds = String.join(",", configedProtocols);
        }

        if (StringUtils.isEmpty(protocolIds)) {
    
    
            // 如果配置中心没有配置协议,就取默认的协议
            if (CollectionUtils.isEmpty(protocols)) {
    
    
                setProtocols(
                        ConfigManager.getInstance().getDefaultProtocols()
                                .filter(CollectionUtils::isNotEmpty)
                                .orElseGet(() -> {
    
    
                                    ProtocolConfig protocolConfig = new ProtocolConfig();
                                    protocolConfig.refresh();
                                    return new ArrayList<>(Arrays.asList(protocolConfig));
                                })
                );
            }
        } else {
    
    
            // 如果配置了
            String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
            List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();

            // 把从配置中心配置的协议添加到服务的协议列表中去
            Arrays.stream(arr).forEach(id -> {
    
    
                if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
    
    
                    tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> {
    
    
                        ProtocolConfig protocolConfig = new ProtocolConfig();
                        protocolConfig.setId(id);
                        protocolConfig.refresh();
                        return protocolConfig;
                    }));
                }
            });
            if (tmpProtocols.size() > arr.length) {
    
    
                throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
                        .size() + " registries!");
            }
            setProtocols(tmpProtocols);
        }
    }

checkApplication()

Si aucune application n'est configurée, créez une instance ApplicationConfig et affectez-la à ConfigManager ;

protected void checkApplication() {
    
    
        // for backward compatibility
        createApplicationIfAbsent();
		//...省略不重要代码
    }
 private void createApplicationIfAbsent() {
    
    
        if (this.application != null) {
    
    
            return;
        }
        ConfigManager configManager = ConfigManager.getInstance();
        setApplication(
                configManager
                        .getApplication()
                        .orElseGet(() -> {
    
    
                            ApplicationConfig applicationConfig = new ApplicationConfig();
                            applicationConfig.refresh();
                            return applicationConfig;
                        })
        );
    }
    

ServiceConfig#refresh()

  • La logique de this.refresh() est la même que la logique de code d'actualisation de ConfigCenterConfig ;
  • Les attributs de l'objet ServiceConfig peuvent avoir des valeurs ou ne pas en avoir. Dans ce cas, les valeurs d'attribut doivent être obtenues à partir d'autres emplacements pour écraser les attributs.
  • ServiceConfig lui-même a de nombreuses configurations, et la valeur de configuration avec la priorité la plus élevée est obtenue en actualisant ; par exemple, timeout, si cette valeur n'est pas configurée dans l'annotation, la configuration sera obtenue à partir d'autres endroits ;
  • La priorité de couverture, de grande à petite, est variable système -> configuration de l'application du centre de configuration -> configuration globale du centre de configuration -> annotation ou définie dans xml -> fichier dubbo.properties
  • Mettre à jour l'attribut correspondant à la méthode set sur le ServiceConfig actuel à la valeur de priorité la plus élevée
public void refresh() {
    
    
        try {
    
    
            //TODO : 都没启动configCenter,配置中心的配置是怎么拿到的????
            CompositeConfiguration compositeConfiguration = Environment.getInstance().getConfiguration(getPrefix(), getId());

            // 表示XxConfig对象本身- AbstractConfig
            Configuration config = new ConfigConfigurationAdapter(this);

            if (Environment.getInstance().isConfigCenterFirst()) {
    
    
                // The sequence would be: SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
                compositeConfiguration.addConfiguration(4, config);
            } else {
    
    
                // The sequence would be: SystemConfiguration -> AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> PropertiesConfiguration
                compositeConfiguration.addConfiguration(2, config);
            }

            // loop methods, get override value and set the new value back to method
            //
            Method[] methods = getClass().getMethods();
            for (Method method : methods) {
    
    
                // 是不是setXX()方法
                if (MethodUtils.isSetter(method)) {
    
    
                    // 获取xx配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig.
                    if (StringUtils.isNotEmpty(value) && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value)) {
    
    
                        method.invoke(this, ClassUtils.convertPrimitive(method.getParameterTypes()[0], value));
                    }
                  // 是不是setParameters()方法
                } else if (isParametersSetter(method)) {
    
    
                    // 获取parameter配置项的value
                    String value = StringUtils.trim(compositeConfiguration.getString(extractPropertyName(getClass(), method)));
                    if (StringUtils.isNotEmpty(value)) {
    
    
                        Map<String, String> map = invokeGetParameters(getClass(), this);
                        map = map == null ? new HashMap<>() : map;
                        map.putAll(convert(StringUtils.parseParameters(value), ""));
                        invokeSetParameters(getClass(), this, map);
                    }
                }
            }
        } catch (Exception e) {
    
    
            logger.error("Failed to override ", e);
        }
    }

À ce stade, le processus principal d'exportation des services pour déterminer les paramètres de configuration des services est terminé. Le code est très bien écrit et la polyvalence est très forte ;

Résumer

La détermination des paramètres de configuration n'est que la première étape de l'export du service, la technologie de réflexion reste une technologie incontournable, qui s'utilise en bas du framework de base, ce qui est une lourde responsabilité ;

Je suppose que tu aimes

Origine blog.csdn.net/yaoyaochengxian/article/details/123488452
conseillé
Classement