Registros de aprendizaje de Dubbo (10) --- Procesamiento de la configuración del registro de exportación del servicio y conversación sobre el uso del modo constructor

exportación de servicios

Proceso general de exportación del servicio Dubbo

  1. Cada anotación de servicio de Dubbo corresponde a un objeto ServiceBean. Cada objeto ServiceBean implementa la interfaz Spring ApplicationListener. Cuando se inicia el proyecto Spring, se activará un evento de actualización de contexto ContextRefreshEvent. El método de activación es el método onApplicationEvent, ServiceBean onApplicationEvent En el método , se llamará a ServiceBean#export(), y luego se llamará al método ServiceConfig#export() de la clase principal para exportar el servicio
  2. Determinará los parámetros de configuración de cada ServiceBean, como el tiempo de espera, el protocolo, etc.. La configuración de estos parámetros se puede configurar en los siguientes lugares: 2.1 Parámetros
    operativos del entorno JVM, especifique los parámetros mediante -D
    2.2 El centro de configuración puede configurar el global configuración del proyecto Y configuración de la aplicación, que es equivalente a un archivo Dubbo.properties compartido distribuido;
    2.3 La anotación @Service puede especificar parámetros;
    2.4 En el proyecto, el archivo de configuración dubbo.properties especificado;
    tantos lugares pueden especificar parámetros de configuración, cuando se exporta el servicio, es necesario determinar qué parámetros de configuración utiliza cada Servicio, es decir, determinar los parámetros con mayor prioridad;
  3. Cargue y determine la información del centro de registro;
  4. Arrancar el contenedor según el Protocolo configurado, el protocolo Dubbo corresponde a Netty, http corresponde a tomcat/jetty, y en proceso de recibir solicitudes, recibir solicitudes según nuestra configuración, como eventos de tiempo de espera, número máximo de conexiones, etc. ;
  5. Después de iniciar el contenedor, la configuración del servicio de cada ServiceBean se registrará en el centro de registro y, al mismo tiempo, se registrará para monitorear la configuración del servicio y monitorear los cambios de configuración, estos son los procesos principales
    . determinar los parámetros de configuración del servicio => iniciar el contenedor => registrarse en el Centro de Registro;
    public synchronized void export() {
    
    
    	//确定服务参数
        checkAndUpdateSubConfigs();

        // 检查服务是否需要导出
        if (!shouldExport()) {
    
    
            return;
        }

        // 检查是否需要延迟发布
        if (shouldDelay()) {
    
    
            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
        } else {
    
    
            // 导出服务
            doExport();
        }
    }

Ideas de exportación de servicios

Hay varias cosas que hacer para la exportación de servicios:

  1. Determinar los parámetros del servicio.
  2. Determinar los protocolos soportados por el servicio.
  3. Construir la URL final del servicio
  4. De acuerdo con los diferentes protocolos admitidos por el servicio, inicie diferentes servidores para recibir y procesar solicitudes
  5. Registre la URL del servicio en el centro de registro
  6. Debido a que Dubbo admite la configuración dinámica de los parámetros del servicio, es necesario vincular un Listener para monitorear si los parámetros del servicio se han modificado cuando se exporta el servicio. Si se encuentra alguna modificación, la exportación debe volver a exportarse.

Determinar los parámetros del servicio.

Escribí un artículo separado en el blog anterior, así que no repetiré la descripción.
Una breve descripción del proceso:

  1. Parámetros completos;
  2. Actualizar los parámetros de configuración;
    2.1 Obtener los parámetros de configuración del centro de configuración, como la dirección del centro de configuración; y actualizar los parámetros del centro de configuración
    2.2 Obtener la configuración global y la configuración de la aplicación del centro de configuración, y ponerlos en el dos atributos de mapa de la configuración externa y la configuración externa de la aplicación del entorno;
    2.3 Actualizar todos los parámetros de la clase de configuración Dubbo; ==>ApplicationConfig, MonitorConfig, ModuleConfig, ProtocolConfig, RegistryConfig, ProviderConfig, ConsumerConfig
    (Nota: en el proceso de actualización de parámetros, especifique el nivel de prioridad del servicio parámetros, configuración del entorno JVM > centro de configuración Configuración de la aplicación de la aplicación > centro de configuración Configuración global > configuración de parámetros de anotación > configuración del archivo dubbo.properties)
  3. Cree una clase de configuración de proveedor de configuración, administrada por ConfigManager
  4. Crear y establecer la clase de configuración de protocolo, administrada por Configmanager
  5. Crear y configurar la aplicación, administrada por ConfigManager;
  6. La actualización del parámetro ServiceConfig representado por la anotación @Service, los valores de los parámetros de configuración establecidos en este momento son todos de la más alta prioridad.
  7. Algunas configuraciones de Mock, Stub, etc.;

Manejar la configuración del registro

Un proyecto puede configurar múltiples registros y Dubbo convertirá estas configuraciones de registro en RegistryConfigs individuales. En la etapa de determinación de los parámetros de configuración del servicio, cada RegistryConfig obtiene el parámetro de mayor prioridad,
propósito: procesar RegistryConfig, analizar cada configuración de registro en URL individuales y, finalmente, devolver un conjunto de URL;

private void doExportUrls() {
    
    
        // 得到url,注册服务也是一个服务,所以也会有对应的url,通过调用该url完成服务注册
        List<URL> registryURLs = loadRegistries(true);   //
		
		//...后面的也是重点代码,但与注册中心处理无关;
    }

cargarRegistros(verdadero)

Trabajar:

  1. Atraviese la clase de configuración del registro;
  2. Si la clase de configuración del centro de registro no establece la dirección de la dirección, se utilizará la dirección anónima 0.0.0.0
  3. Si la dirección de la clase de configuración del centro de registro es "N/A", salga del bucle y ejecute la siguiente clase de configuración;
  4. Si la dirección de la clase de configuración del registro no es "N/A", entonces
    4.1 obtiene los parámetros de ApplicationConfig y los coloca en el mapa (recorriendo el método Method)
    4.2 obtiene los parámetros de RegistryConfig y los coloca en el mapa; (atravesando el método Método)
    registro La clase de configuración central empaqueta el nombre de usuario y la contraseña del usuario en el mapa;
    4.3 Agregue el valor de la ruta y arréglelo como RegistryService.class.getName();
    4.4 Obtenga la información de la versión de Dubbo y colóquela en el mapa;
    4.5 Construir la URL y pasar Dirección + parámetro (UrlUtils.parseURLs(dirección, mapa));
    4.6 Pasar el valor del parámetro de protocolo y el nombre de protocolo de la URL para construir la URL final;
    4.7 Obtener el valor del registro del proveedor de la URL, verdadero para registrarse, falso de lo contrario, consumidor, para juzgar el valor de suscripción, verdadero para suscribirse, falso para no suscribirse al centro de registro;
    protected List<URL> loadRegistries(boolean provider) {
    
    
        // check && override if necessary
        List<URL> registryList = new ArrayList<URL>();
        if (CollectionUtils.isNotEmpty(registries)) {
    
    
            for (RegistryConfig config : registries) {
    
    
                String address = config.getAddress();
                // 如果注册中心没有配地址,则地址为0.0.0.0
                if (StringUtils.isEmpty(address)) {
    
    
                    address = ANYHOST_VALUE;
                }
                // 如果注册中心的地址不是"N/A"
                if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
    
    
                    Map<String, String> map = new HashMap<String, String>();
                    // 把application中的参数放入map中,注意,map中的key是没有prefix的
                    appendParameters(map, application);
                    // 把config中的参数放入map中,注意,map中的key是没有prefix的
                    // config是RegistryConfig,表示注册中心
                    appendParameters(map, config);
                    // 此处path值固定为RegistryService.class.getName(),因为现在是在加载注册中心
                    map.put(PATH_KEY, RegistryService.class.getName());
                    // 把dubbo的版本信息和pid放入map中
                    appendRuntimeParameters(map);

                    // 如果map中如果没有protocol,那么默认为dubbo
                    if (!map.containsKey(PROTOCOL_KEY)) {
    
    
                        map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
                    }

                    // 构造注册中心url,地址+参数
                    List<URL> urls = UrlUtils.parseURLs(address, map);

                    for (URL url : urls) {
    
    
                        url = URLBuilder.from(url)
                                .addParameter(REGISTRY_KEY, url.getProtocol())
                                .setProtocol(REGISTRY_PROTOCOL)
                                .build();

                        // 这里是服务提供者和服务消费者区别的逻辑
                        // 如果是服务提供者,获取register的值,如果为false,表示该服务不注册到注册中心
                        // 如果是服务消费者,获取subscribe的值,如果为false,表示该引入的服务不订阅注册中心中的数据
                        if ((provider && url.getParameter(REGISTER_KEY, true))
                                || (!provider && url.getParameter(SUBSCRIBE_KEY, true))) {
    
    
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

UrlUtils.parseURLs(dirección, mapa)

Propósito: Crear inicialmente una URL basada en dirección y parámetros, si el formato de la dirección es: "192.168.2.110;192.168.2.111", se resolverá en dos URL;

	//REGISTRY_SPLIT_PATTERN = ";"
    public static List<URL> parseURLs(String address, Map<String, String> defaults) {
    
    
        if (address == null || address.length() == 0) {
    
    
            return null;
        }
        String[] addresses = REGISTRY_SPLIT_PATTERN.split(address);
        if (addresses == null || addresses.length == 0) {
    
    
            return null; //here won't be empty
        }
        List<URL> registries = new ArrayList<URL>();
        for (String addr : addresses) {
    
    
            registries.add(parseURL(addr, defaults));
        }
        return registries;
    }

Atraviesa el protocolo ProtocolConfig

  1. Obtener la colección de URL del centro de registro;
  2. Atraviesa el protocolo ProtocolConfig;
  3. Obtener PathKey, formato: group / contextPath / path :version; contextPath es el nombre de la aplicación, path es el nombre completo de la ruta;
  4. Cree una instancia de ProviderModel, que incluya la clave de la ruta, la clase de implementación del servicio y la información de la clase de interfaz; ApplicationModel indica que la interfaz del servicio y la clase de implementación de la interfaz en la aplicación brindan un servicio;
  5. Tome pathKey como clave y la instancia de providerModel como valor, y póngalo en el mapa que almacena en caché PROVIDER_SERVICES
  6. Cada protocolo exporta un servicio separado, que se registra en cada centro de registro, y un servicio corresponde a uno o más protocolos;
	private List<ProtocolConfiguration> protocols;
	
    private void doExportUrls() {
    
    
        List<URL> registryURLs = loadRegistries(true);  
        for (ProtocolConfig protocolConfig : protocols) {
    
    
            //获取pathKey
            String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
			//创建ProviderModel实例
            ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
            //放入缓存
            ApplicationModel.initProviderModel(pathKey, providerModel);
			//一个服务,对应多种协议,每种一些导出一次,注册到注册中心;
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

Hablando sobre el modo constructor y el uso

Concepto general: el modo constructor es crear un objeto complejo paso a paso, lo que permite a los usuarios construirlos solo especificando el tipo y el contenido de los objetos complejos, y los usuarios no necesitan conocer los detalles específicos de la construcción interna
.

	url = URLBuilder.from(url).addParameter(REGISTRY_KEY, url.getProtocol()).setProtocol(REGISTRY_PROTOCOL).build();
	//获取参数, 创建构造器对象;
    public static URLBuilder from(URL url) {
    
    
        String protocol = url.getProtocol();
        String username = url.getUsername();
        String password = url.getPassword();
        String host = url.getHost();
        int port = url.getPort();
        String path = url.getPath();
        Map<String, String> parameters = new HashMap<>(url.getParameters());
        return new URLBuilder(
                protocol,
                username,
                password,
                host,
                port,
                path,
                parameters);
    }
    //添加参数,返回的还是自身实例
     public URLBuilder addParameter(String key, String value) {
    
    
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
    
    
            return this;
        }
        // if value doesn't change, return immediately
        if (value.equals(parameters.get(key))) {
    
     // value != null
            return this;
        }

        parameters.put(key, value);
        return this;
    }
    //设置协议参数, 返回的还是自身实例
    public URLBuilder setProtocol(String protocol) {
    
    
        this.protocol = protocol;
        return this;
    }
    //使用构造器实例,创建URL对象。
    public URL build() {
    
    
        port = port < 0 ? 0 : port;
        // trim the leading "/"
        int firstNonSlash = 0;
		//...
        return new URL(protocol, username, password, host, port, path, parameters);
    }

  • Al igual que en los negocios, new Object(), y luego configurar uno por uno, la cantidad de código es muy grande y se usa en muchos lugares para crear objetos complejos.
  • Hay un campo más en la tabla de la base de datos y un campo más en el objeto de la entidad, lo cual es problemático y debe cambiarse en todas partes, lo cual es muy inconveniente. Por lo tanto, vale la pena aprender este constructor de URLBuidler.
  • Por ejemplo, si se necesita agregar un campo a la URL, solo se debe modificar en el constructor de Builder sin modificar nuestro código comercial. Reduzca la cantidad de cambios de código,
    cumpla con el principio de apertura y cierre, y el principio de responsabilidad única,
    maneje la configuración del registro: conviértalo en objetos de URL uno por uno de acuerdo con RegistryConfig, y finalmente devuelva una colección de URL;

Supongo que te gusta

Origin blog.csdn.net/yaoyaochengxian/article/details/123512598
Recomendado
Clasificación