Analyse du code source liée à la configuration de routage dynamique Nacos (1)

1: Configurer les informations nacos associées

D'autres informations ont été omises

Gateway.yml dans le projet

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: Créer des classes d'entités associées

filtre

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<>();

}

Affirmation:

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<>();

}

Classe de routage

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: Ajouter un moniteur

Surveiller les informations de configuration des 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;
    }
}

Les nacos de code ci-dessus peuvent ajouter dynamiquement le routage et les amis peuvent l'utiliser directement

============================= ligne de division =================== ===========================

4: Analyse du code source pertinent

Dans la configuration ci-dessus, chargez d'abord les informations dans api-gatway.yaml, puis chargez les informations de configuration dans routes-api-gatway.yaml. Le principe est le même, mais l'écouteur est routes-api-gatway.yaml (il est au format json)
ApplicationEventPublisherAware est une interface de publication d'événements, comprenant des événements, des éditeurs et des écouteurs. L'éditeur de l'événement ici est la classe fournie avec la passerelle, RefreshRoutesEvent, et l'événement consiste à actualiser l'itinéraire.


Indépendamment de l'initialisation du routage ou de l'actualisation du routage, la première étape consiste à obtenir les informations pertinentes des nacos. ConfigService est obtenu par la classe de fabrique statique NacosFactory

Entrez ConfigFactory et trouvez que ConfigService est NacosConfigService obtenu par mécanisme de réflexion, NacosConfigService implémente ConfigService

Entrez NacosConfigService, la méthode de construction à l'intérieur effectue les affectations pertinentes des nacos, y compris les espaces de noms, etc. Jusqu'à présent, on peut voir que nacos a été connecté avec succès et que la classe de configuration de nacos a été renvoyée.

Regardons la deuxième phrase du code String configInfo = configService.getConfig (dataId, groupId, 5000) Cette phrase signifie en fait que la classe de configuration nacos obtient les informations du fichier de configuration en fonction de dataId et groupId, qui est le contenu yaml que vous configurez dans les nacos interface de visualisation.

Regardez le code ci-dessous

Regardez directement la méthode getConfigInner, cette méthode obtient d'abord les informations de configuration Nacos locales, sinon, puis obtient les informations de configuration sur le serveur

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

Obtenez les informations de configuration sur le serveur nacos.

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

Entrez le getServerConfig de ClientWorker

La méthode principale de ClientWorker agent.httpGet (Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode (), readTimeout), cliquez pour entrer la
classe ServerHttpAgent ServerHttpAgent pour l'appel http

La classe HttpSimpleClient est appelée dans ServerHttpAgent pour appeler Nacos Open API afin d'obtenir la configuration à partir de Nacos Server. La
deuxième fois, voici l'url: http: //xx.xx.xx.xx: 8848 / nacos / v1 / cs / configs? DataId = routes-api-gatway & group = ROUTE_GROUP & tenant = dev , vous pouvez également utiliser postman pour appeler, en fait, ce qui est renvoyé est votre fichier de configuration de api-gatway.yaml ou routes-api-gatway.yaml dans nacos

 

 

Le fichier de configuration de routes-api-gatway.yaml dans nacos

 

À ce stade, les deux premières lignes de code ont été exécutées. Ce qui suit est d'analyser puis de publier l'événement.

String configInfo = configService.getConfig (dataId, groupId, 5000) La chaîne de route retournée par la méthode est analysée dans une collection de classes d'entité de route, et la route est analysée et affectée à la classe RouteDefinition dans une boucle,

Route, assertion, URL et autres paramètres dans RouteDefinition

La vérification suivante, ajoutez une nouvelle route avec l'identifiant de service4 et publiez-la, vous constaterez que le code lit automatiquement la dernière configuration et effectue une analyse de la route pour mettre à jour la route

 

 

Je suppose que tu aimes

Origine blog.csdn.net/CarryBest/article/details/112985659
conseillé
Classement