Análisis de código fuente relacionado con la configuración de enrutamiento dinámico de Nacos (1)

1: Configurar la información de nacos relacionada

Se ha omitido otra información

Gateway.yml en el proyecto

nacos:
  server-addr:xx.xx.xx.xx:8848
  namespace: dev

#省略其他代码。。。。。。。。。

#动态路由相关配置
dynamic:
  route:
    data-id: routes-${spring.application.name}.yaml
    group: ROUTE_GROUP
    server-addr: xx.xx.xx.xx:8848
    namespace: dev

 

2: crear clases de entidad relacionadas

filtrar

package com.carry.www.entity;

/**
 * 过滤器实体类
 *
 */
import lombok.Data;

import java.util.LinkedHashMap;
import java.util.Map;

@Data
public class FilterEntity {

  // 过滤器对应的Name
  private String name;

  // 路由规则
  private Map<String, String> args = new LinkedHashMap<>();

}

Afirmación:

package com.carry.www.entity;

import lombok.Data;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 路由断言实体类
 *
 */
@Data
public class PredicateEntity {
  // 断言对应的Name
  private String name;

  // 断言规则
  private Map<String, String> args = new LinkedHashMap<>();

}

Clase de enrutamiento

package com.carry.www.entity;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 * 路由实体类
 *
 */
@Data
public class RouteEntity {
  // 路由id
  private String id;

  // 路由断言集合
  private List<PredicateEntity> predicates = new ArrayList<>();

  // 路由过滤器集合
  private List<FilterEntity> filters = new ArrayList<>();

  // 路由转发的目标uri
  private String uri;

  // 路由执行的顺序
  private int order = 0;
}

3: Agregar monitor

Monitorear la información de configuración de nacos

package com.carry.www.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.carry.www.entity.FilterEntity;
import com.carry.www.entity.PredicateEntity;
import com.carry.www.entity.RouteEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 从Nacos获取动态路由
 * 实现ApplicationEventPublisherAware发布接口来发布路由更新事件
 */
@Configuration
@Slf4j
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {

    @Value("${dynamic.route.server-addr}")
    private String serverAddr;

    @Value("${nacos.namespace}")
    private String namespace;

    @Value("${dynamic.route.data-id}")
    private String dataId;

    @Value("${dynamic.route.group}")
    private String groupId;

    // 保存、删除路由服务
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * @return
     * @Author carryer
     * @Description 获取nacos配置服务
     * @Date
     * @Param
     **/
    public ConfigService getNacosConfigInfo() throws Exception {
        Properties properties = new Properties();
        properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverAddr);
//        properties.setProperty(PropertyKeyConst.USERNAME, username);
//        properties.setProperty(PropertyKeyConst.PASSWORD, password);
        properties.setProperty(PropertyKeyConst.NAMESPACE, namespace);
        ConfigService configService = NacosFactory.createConfigService(properties);

        return configService;
    }

    /**
     * @return
     * @Author carryer
     * @Description 初始化路由
     * @Date
     * @Param
     **/
    @Bean
    public void initRouting() {
        try {
            ConfigService configService = this.getNacosConfigInfo();
            String configInfo = configService.getConfig(dataId, groupId, 5000);
            if (null != configInfo) {
                List<RouteEntity> list = JSONObject.parseArray(configInfo).toJavaList(RouteEntity.class);
                for (RouteEntity route : list) {
                    update(assembleRouteDefinition(route));
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            e.printStackTrace();
        }
    }

    /**
     * @return
     * @Author carryer
     * @Description 刷新路由
     * @Date
     * @Param
     **/
    @Bean
    public void refreshRouting() {
        try {
            ConfigService configService = this.getNacosConfigInfo();
            //监听路由变化
            configService.addListener(
                    dataId,
                    groupId,
                    new Listener() {
                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        @Override
                        public void receiveConfigInfo(String configInfo) {
                            try {
                                log.info(configInfo);
                                if (null != configInfo) {
                                    List<RouteEntity> list =
                                            JSONObject.parseArray(configInfo).toJavaList(RouteEntity.class);
                                    //更新路由表
                                    for (RouteEntity route : list) {
                                        update(assembleRouteDefinition(route));
                                    }
                                }
                            } catch (Exception e) {
                                log.error(e.getMessage(), e);
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            e.printStackTrace();
        }
    }

    /**
     * @return
     * @Author carryer
     * @Description 路由更新
     * @Date
     * @Param
     **/
    private void update(RouteDefinition routeDefinition) throws Exception {
        //先删除路由
        routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
        //再保存路由
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        //发布事件 发布者是RefreshRoutesEvent 事件是刷新路由
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * @return
     * @Author carryer
     * @Description 实体信息解析
     * @Date
     * @Param
     **/
    private RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
        RouteDefinition definition = new RouteDefinition();
        // ID
        definition.setId(routeEntity.getId());

        // Predicates断言
        List<PredicateDefinition> pdList = new ArrayList<>();
        for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {
            PredicateDefinition predicateDefinition = new PredicateDefinition();
            predicateDefinition.setArgs(predicateEntity.getArgs());
            predicateDefinition.setName(predicateEntity.getName());
            pdList.add(predicateDefinition);
        }
        definition.setPredicates(pdList);

        // Filters过滤器
        List<FilterDefinition> fdList = new ArrayList<>();
        for (FilterEntity filterEntity : routeEntity.getFilters()) {
            FilterDefinition filterDefinition = new FilterDefinition();
            filterDefinition.setArgs(filterEntity.getArgs());
            filterDefinition.setName(filterEntity.getName());
            fdList.add(filterDefinition);
        }
        definition.setFilters(fdList);

        // URI
        URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
        definition.setUri(uri);

        return definition;
    }
}

El código anterior nacos puede agregar enrutamiento dinámicamente, y los amigos pueden usarlo directamente

============================= línea divisoria =================== ==========================

4: Análisis de código fuente relevante

En la configuración anterior, primero cargue la información en api-gatway.yaml y luego cargue la información de configuración en route-api-gatway.yaml. El principio es el mismo, pero el oyente es route-api-gatway.yaml (hay es formato json)
ApplicationEventPublisherAware es una interfaz de publicación de eventos, que incluye eventos, editores y oyentes. El editor del evento aquí es la clase que viene con la puerta de enlace, RefreshRoutesEvent, y el evento es para actualizar la ruta.


Independientemente de inicializar el enrutamiento o actualizar el enrutamiento, el primer paso es obtener la información relevante de nacos. ConfigService se obtiene mediante la clase de fábrica estática NacosFactory

Ingrese a ConfigFactory y encuentre que ConfigService es NacosConfigService obtenido por mecanismo de reflexión, NacosConfigService implementa ConfigService

Ingrese a NacosConfigService, el método de construcción interno realiza las asignaciones relevantes de nacos, incluidos los espacios de nombres, etc. Hasta ahora, se puede ver que nacos se ha conectado correctamente y se ha devuelto la clase de configuración de nacos.

Veamos la segunda oración del código String configInfo = configService.getConfig (dataId, groupId, 5000) Esta oración en realidad significa que la clase de configuración de nacos obtiene información del archivo de configuración de acuerdo con dataId y groupId, que es el contenido de yaml que configura en nacos interfaz de visualización.

Mira el código a continuación

Mire directamente el método getConfigInner, este método primero obtiene la información de configuración local de Nacos, si no, luego obtiene la información de configuración en el servidor

String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);

Obtenga la información de configuración en el servidor nacos.

String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
Nacos的ClientWorker类进行赋值操作,调用getServerConfig方法获取配置返回配置数组

Ingrese getServerConfig de ClientWorker

El método principal en ClientWorker agent.httpGet (Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode (), readTimeout), haga clic para ingresar ServerHttpAgent
ServerHttpAgent clase para llamada http

La clase HttpSimpleClient se llama en ServerHttpAgent para llamar a Nacos Open API y obtener la configuración del servidor Nacos. La
segunda vez aquí es la URL: http: //xx.xx.xx.xx: 8848 / nacos / v1 / cs / configs? DataId = route-api-gatway & group = ROUTE_GROUP & tenant = dev , también puede usar postman para llamar, de hecho, lo que se devuelve es su archivo de configuración de api-gatway.yaml o route-api-gatway.yaml en nacos

 

 

El archivo de configuración de routes-api-gatway.yaml en nacos

 

En este punto, se han ejecutado las dos primeras líneas de código. Lo siguiente es analizar y luego publicar el evento.

String configInfo = configService.getConfig (dataId, groupId, 5000) La cadena de ruta devuelta por el método se analiza en una colección de clases de entidad de ruta, y la ruta se analiza y se asigna a la clase RouteDefinition en un bucle,

Ruta, afirmación, URL y otras configuraciones en RouteDefinition

La siguiente verificación, agrega una nueva ruta con id de servicio4 y publícala, encontrarás que el código lee automáticamente la última configuración y realiza análisis de ruta para actualizar la ruta

 

 

Supongo que te gusta

Origin blog.csdn.net/CarryBest/article/details/112985659
Recomendado
Clasificación