当前位置:网站首页>Démarrer avec Apache shenyu
Démarrer avec Apache shenyu
2022-06-25 11:05:00 【Manuel de programmation de Xiaoxian】
Introduction
J'ai récemment appris quelque chose sur la passerelle,J'ai trouvé.shenyuCette asynchrone、Haute performance、Translingue、Réactif API Passerelle. Il a fallu un jour ou deux pour commencer,Notez - le ici..
Pour plus de détails, veuillez consulter le site officiel
Fonctionnement local
Deux modules sont nécessaires avant le démarrage local:
1-shenyu-admin : Gestion de l'arrière - plan de la configuration des plug - ins et autres informations,La classe de démarrage est la suivante:
ShenyuAdminBootstrap
2-shenyu-bootstrap : Pour lancer le projet,La classe de démarrage est la suivante:
ShenyuBootstrapApplication
3-Vous devez configurer avant de commencerdbInformations sur,Ici, j'ai choisimysql,Modifiershenyu-adminEn bas.application.ymlLe contenu est le suivant:,Puis configurerapplication-mysql.ymlLes informations de connexion dans.
spring:
profiles:
active: mysql
4-Enfin, initialiserSQLScript:
incubator-shenyu/db/init/mysql/schema.sql
5-Exécuter deux classes de démarrage Adresse d'accès: http://localhost:9095/#/home Nom d'utilisateur Mot de passe admin 123456
Ici, tout le Service de passerelle est lancé localement. , Mais nous n'avons pas encore accès à nos propres services. .
Démarrer avec l'accès au service
Nous pouvons le faire directementshenyu-examples Trouvé le serveur auquel vous souhaitez accéder demo.Par exemple,http,dubbo,motan,springmvc,springcloudAttendez un peu!.
J'ai choisishenyu-examples-httpPour tester,En fait, c'est unspringbootProjets. Parce que nous avons finalement besoin d'un accès par passerelle , La passerelle doit être consciente , Il faut donc d'abord faire quelques configurations (example Déjà configuré ,Possibilité de modifier, J'ai modifié contextPathEtappName)
application.yml:
shenyu:
register:
registerType: http #zookeeper #etcd #nacos #consul
serverLists: http://localhost:9095 #localhost:2181 #http://localhost:2379 #localhost:8848
props:
username: admin
password: 123456
client:
http:
props:
contextPath: /api/test
appName: testApp
port: 8189
Il s'agit principalement de configurer comment les services que nous avons lancés sont enregistrés dans la passerelle. : registerType Les types de représentation comprennent http,zk,nacosAttendez.,La valeur par défaut ici esthttp. client Certaines identités du Service actuel dans la passerelle sont configurées . Puis vous pouvez démarrer l'application .Ensuite, vous pouvez utiliserpostmanEffectuer un test d'appel.Peut être obtenu à partir dedemoDansHttpTestController Sélectionnez une interface pour accéder directement et via la passerelle pour tester .

Accès direct à l'application actuelle http://localhost:8189/test/payment:

Accès par passerelle http://localhost:9195/api/test/test/payment:

L'adresse d'accès vous permet de spécifier contextPath Ce qui fonctionne . Si le préfixe de chemin pour l'accès basé sur la passerelle n'est pas configuré par nous contextPath L'erreur suivante est affichée : "message": "divide:Can not find selector, please check your configuration!"
Analyse du principe d'application de l'accès
Après avoir fait l'introduction la plus élémentaire , Je ne peux m'empêcher d'explorer la raison d'être . C'est ainsi que l'accès http exampleDepom Il a été trouvé dans le fichier qu'il a introduit un starter(springbootDansstarterJe ne vous présenterai pas) Adresse officielle de présentation:shenyu.apache.org/zh/docs/des…
<dependency>
<groupId>org.apache.shenyu</groupId>
<artifactId>shenyu-spring-boot-starter-client-springmvc</artifactId>
<version>${project.version}</version>
</dependency>
Et trouve ça.starterModule,Découverteshenyu D'autres starter,Par exemple,dubboDe,motanDe,Peut permettreRPC Le cadre se connecte à notre passerelle .

On continue à regarder shenyu-spring-boot-starter-client-springmvc.InShenyuSpringMvcClientConfigurationPlus d'un est défini dansbean,Voir principalement
SpringMvcClientBeanPostProcessor
C'est fait.BeanPostProcessorInterface,InbeanInstanciation、Injection dépendante、 L'exécution appelle à la fin de l'initialisation postProcessAfterInitializationMéthodes.Les sources spécifiques sont les suivantes:
@Override
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
// Filter out is not controller out
if (Boolean.TRUE.equals(isFull) || !hasAnnotation(bean.getClass(), Controller.class)) {
return bean;
}
//Obtenir le chemin,Obtenir d'abordShenyuSpringMvcClientNote, Sinon, obtenez RequestMappingOui.
final ShenyuSpringMvcClient beanShenyuClient = AnnotationUtils.findAnnotation(bean.getClass(), ShenyuSpringMvcClient.class);
final String superPath = buildApiSuperPath(bean.getClass());
// Compatible with previous versions
if (Objects.nonNull(beanShenyuClient) && superPath.contains("*")) {
publisher.publishEvent(buildMetaDataDTO(beanShenyuClient, pathJoin(contextPath, superPath)));
return bean;
}
// Méthode d'obtention obtenir d'abord ShenyuSpringMvcClientNotes,Analysepath
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
for (Method method : methods) {
final RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
ShenyuSpringMvcClient methodShenyuClient = AnnotationUtils.findAnnotation(method, ShenyuSpringMvcClient.class);
methodShenyuClient = Objects.isNull(methodShenyuClient) ? beanShenyuClient : methodShenyuClient;
// the result of ReflectionUtils#getUniqueDeclaredMethods contains method such as hashCode, wait, toSting
// add Objects.nonNull(requestMapping) to make sure not register wrong method
//
if (Objects.nonNull(methodShenyuClient) && Objects.nonNull(requestMapping)) {
publisher.publishEvent(buildMetaDataDTO(methodShenyuClient, buildApiPath(method, superPath)));
}
}
return bean;
}
// En fin de compte, l'annotation résolue est construite comme suit: MetaDataRegisterDTO,Et à traverspublisher.publishEventEnvoyez - le
private MetaDataRegisterDTO buildMetaDataDTO(@NonNull final ShenyuSpringMvcClient shenyuSpringMvcClient, final String path) {
return MetaDataRegisterDTO.builder()
.contextPath(contextPath) //ymlConfiguré
.appName(appName) //ymlConfiguré
.path(path)
.pathDesc(shenyuSpringMvcClient.desc())
.rpcType(RpcTypeEnum.HTTP.getName())
.enabled(shenyuSpringMvcClient.enabled())
.ruleName(StringUtils.defaultIfBlank(shenyuSpringMvcClient.ruleName(), path))
.registerMetaData(shenyuSpringMvcClient.registerMetaData())
.build();
}
ShenyuClientRegisterEventPublisher
Au - dessuspublisher.publishEventÇa veut direShenyuClientRegisterEventPublisher.
Il est basé surDisruptor Un modèle de production et de consommation mis en œuvre par une file d'attente de haute performance .
OffrepublishEvent Comment produire un message
Et offreQueueConsumer Pour une consommation asynchrone
Qui finira parRegisterClientConsumerExecutorPour consommer
private final ShenyuClientRegisterEventPublisher publisher = ShenyuClientRegisterEventPublisher.getInstance();
//Méthode de démarrage,SpécifiéShenyuClientMetadataExecutorSubscriberEtShenyuClientURIExecutorSubscriber,InRegisterClientConsumerExecutor Il est utilisé pour la consommation .
public void start(final ShenyuClientRegisterRepository shenyuClientRegisterRepository) {
RegisterClientExecutorFactory factory = new RegisterClientExecutorFactory();
factory.addSubscribers(new ShenyuClientMetadataExecutorSubscriber(shenyuClientRegisterRepository));
factory.addSubscribers(new ShenyuClientURIExecutorSubscriber(shenyuClientRegisterRepository));
providerManage = new DisruptorProviderManage<>(factory);
providerManage.startup();
}
//ShenyuClientMetadataExecutorSubscriber Le contenu est de savoir où aller shenyu-adminInscriptionMetadataC'est.
//ShenyuClientRegisterRepository C'est là questarterDéfini dansbean,Voici une introduction,De toute façon, nousexampleCe que j'aiHttpClientRegisterRepository
private final ShenyuClientRegisterRepository shenyuClientRegisterRepository;
/**
* Instantiates a new shenyu client metadata executor subscriber.
*
* @param shenyuClientRegisterRepository the shenyu client register repository
*/
public ShenyuClientMetadataExecutorSubscriber(finalShenyuClientRegisterRepository shenyuClientRegisterRepository) {
this.shenyuClientRegisterRepository = shenyuClientRegisterRepository;
}
@Override
public DataType getType() {
return DataType.META_DATA;
}
//Le type de message estDataType.META_DATADe, Le consommateur finira par appeler cette méthode pour traiter le message
@Override
public void executor(final Collection<MetaDataRegisterDTO> metaDataRegisterDTOList) {
for (MetaDataRegisterDTO metaDataRegisterDTO : metaDataRegisterDTOList) {
shenyuClientRegisterRepository.persistInterface(metaDataRegisterDTO);
}
}
// La mise en œuvre concrète est basée sur httpDemandemetaDataEnregistré àadminMoyenne
@Override
public void doPersistInterface(final MetaDataRegisterDTO metadata) {
doRegister(metadata, Constants.META_PATH, Constants.META_TYPE);
}
Adresse de l'interface:
String META_PATH = "/shenyu-client/register-metadata";
Nous pouvonsshenyu-adminDansShenyuClientHttpRegistryController Trouver l'adresse correspondante dans .
shenyu-admin La façon de recevoir de nouveaux changements d'information sera expliquée plus loin. .Voici d'abord.
ContextRegisterListener
Au démarrage publisherProduction moyenneURIRegisterDTOType de message
@Override
public void onApplicationEvent(@NonNull final ContextRefreshedEvent contextRefreshedEvent) {
if (!registered.compareAndSet(false, true)) {
return;
}
if (Boolean.TRUE.equals(isFull)) {
publisher.publishEvent(buildMetaDataDTO());
}
try {
final int mergedPort = port <= 0 ? PortUtils.findPort(beanFactory) : port;
publisher.publishEvent(buildURIRegisterDTO(mergedPort));
} catch (ShenyuException e) {
throw new ShenyuException(e.getMessage() + "please config ${shenyu.client.http.props.port} in xml/yml !");
}
}
private URIRegisterDTO buildURIRegisterDTO(final int port) {
return URIRegisterDTO.builder()
.contextPath(this.contextPath)
.appName(appName)
.protocol(protocol)
.host(IpUtils.isCompleteHost(this.host) ? this.host : IpUtils.getHost(this.host))
.port(port)
.rpcType(RpcTypeEnum.HTTP.getName())
.build();
}
ShenyuClientRegisterRepository
Obtenir des implémentations spécifiques en fonction de la configuration ,Par défauthttp
/**
* New instance shenyu client register repository.
*
* @param shenyuRegisterCenterConfig the shenyu register center config
* @return the shenyu client register repository
*/
public static ShenyuClientRegisterRepository newInstance(final ShenyuRegisterCenterConfig shenyuRegisterCenterConfig) {
if (!REPOSITORY_MAP.containsKey(shenyuRegisterCenterConfig.getRegisterType())) {
//spi Le mécanisme obtient une mise en œuvre concrète ,La nôtre.demo- Oui.HttpClientRegisterRepository
ShenyuClientRegisterRepository result = ExtensionLoader.getExtensionLoader(ShenyuClientRegisterRepository.class).getJoin(shenyuRegisterCenterConfig.getRegisterType());
result.init(shenyuRegisterCenterConfig);
ShenyuClientShutdownHook.set(result, shenyuRegisterCenterConfig.getProps());
REPOSITORY_MAP.put(shenyuRegisterCenterConfig.getRegisterType(), result);
return result;
}
return REPOSITORY_MAP.get(shenyuRegisterCenterConfig.getRegisterType());
}
Ici, notre application a été informée shenyu-admin.
shenyu-admin Comment recevoir des messages mis à jour
shenyu-admin En tant qu'arrière - plan administratif, les données sont stockées dans dbMoyenne, Et synchroniser les données au service de passerelle .
Là - hauthttp example Nous savons déjà que notre service est basé sur ShenyuClientRegisterRepository Comme ça.shenyu-adminPour s'inscrireMetaDataAttendre l'information.
ShenyuClientRegisterRepository Plusieurs implémentations sont instanciées en fonction de notre configuration .Par exemple:http,nacos... Regardez maintenantadmin Voici comment recevoir les messages d'inscription .
Basé surhttp La méthode d'enregistrement est basée sur ShenyuClientHttpRegistryController Interface interne pour recevoir des messages
@PostMapping("/register-metadata")
@ResponseBody
public String registerMetadata(@RequestBody final MetaDataRegisterDTO metaDataRegisterDTO) {
publisher.publish(metaDataRegisterDTO);
return ShenyuResultMessage.SUCCESS;
}
Vous pouvez également regarder la base de nacosMode d'inscription,Si elle est basée surnacosInscription,Etshenyu-admin Qui dépendent shenyu-register-client-server-nacos Module pour écouter les informations d'inscription .
//shenyu admin Initialisation au démarrage bean,Et l'inscriptionShenyuClientRegisterRepositoryRéponse faciale
@Bean(destroyMethod = "close")
public ShenyuClientServerRegisterRepository shenyuClientServerRegisterRepository(final ShenyuRegisterCenterConfig shenyuRegisterCenterConfig,
final List<ShenyuClientRegisterService> shenyuClientRegisterService) {
String registerType = shenyuRegisterCenterConfig.getRegisterType();
ShenyuClientServerRegisterRepository registerRepository = ExtensionLoader.getExtensionLoader(ShenyuClientServerRegisterRepository.class).getJoin(registerType);
RegisterClientServerDisruptorPublisher publisher = RegisterClientServerDisruptorPublisher.getInstance();
Map<String, ShenyuClientRegisterService> registerServiceMap = shenyuClientRegisterService.stream().collect(Collectors.toMap(ShenyuClientRegisterService::rpcType, e -> e));
publisher.start(registerServiceMap);
registerRepository.init(publisher, shenyuRegisterCenterConfig);
return registerRepository;
}
//Basé surnacosClasse d'implémentation pour
NacosClientServerRegisterRepository
//Il est dit ci - dessusbean Il est appelé quand initMéthodes.Enfin, on appellesubscribe Méthode d'écoute
try {
this.configService = ConfigFactory.createConfigService(nacosProperties);
this.namingService = NamingFactory.createNamingService(nacosProperties);
} catch (NacosException e) {
throw new ShenyuException(e);
}
subscribe();
//subscribeLa méthode est finalement appelée à,Est basé surnacosDeAPIPour écouter
private void subscribeMetadata(final String serviceConfigName) {
registerMetadata(readData(serviceConfigName));
LOGGER.info("subscribe metadata: {}", serviceConfigName);
try {
configService.addListener(serviceConfigName, defaultGroup, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(final String config) {
registerMetadata(config);
}
});
} catch (NacosException e) {
throw new ShenyuException(e);
}
}
//Enfin, il sera appelépublisher.publish,Et sur la basehttpInterface pour /register-metadata La mise en œuvre finale est la même .
private void publishMetadata(final String data) {
LOGGER.info("publish metadata: {}", data);
publisher.publish(Lists.newArrayList(GsonUtis.getInstance().fromJson(data, MetaDataRegisterDTO.class)));
}
//Ici.publisher Et ce qui précède décrit publisherLe principe est le même
Est également basé surDisruptor Un modèle de production et de consommation mis en œuvre par une file d'attente de haute performance .
// Le consommateur finira par invoquer MetadataExecutorSubscriberDans
shenyuClientRegisterService.register(metaDataRegisterDTO);
//Ici.register C'est
public String register(final MetaDataRegisterDTO dto) {
//handler plugin selector
String selectorHandler = selectorHandler(dto);
String selectorId = selectorService.registerDefault(dto, PluginNameAdapter.rpcTypeAdapter(rpcType()), selectorHandler);
//handler selector rule
String ruleHandler = ruleHandler();
RuleDTO ruleDTO = buildRpcDefaultRuleDTO(selectorId, dto, ruleHandler);
ruleService.registerDefault(ruleDTO);
//handler register metadata
registerMetadata(dto);
//handler context path
String contextPath = dto.getContextPath();
if (StringUtils.isNotEmpty(contextPath)) {
registerContextPath(dto);
}
return ShenyuResultMessage.SUCCESS;
}
Basé surhttpLa classe d'implémentation pour est:ShenyuClientRegisterDivideServiceImpl
protected void registerMetadata(final MetaDataRegisterDTO dto) {
if (dto.isRegisterMetaData()) {
MetaDataService metaDataService = getMetaDataService();
MetaDataDO exist = metaDataService.findByPath(dto.getPath());
metaDataService.saveOrUpdateMetaData(exist, dto);
}
}
// Il finira dans l'entrepôt , Et a fait un eventPublisher.publishEventFonctionnement, Cette opération consiste à synchroniser l'information sur la passerelle . Plus de détails .
public void saveOrUpdateMetaData(final MetaDataDO exist, final MetaDataRegisterDTO metaDataDTO) {
DataEventTypeEnum eventType;
MetaDataDO metaDataDO = MetaDataTransfer.INSTANCE.mapRegisterDTOToEntity(metaDataDTO);
if (Objects.isNull(exist)) {
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
metaDataDO.setId(UUIDUtils.getInstance().generateShortUuid());
metaDataDO.setDateCreated(currentTime);
metaDataDO.setDateUpdated(currentTime);
metaDataMapper.insert(metaDataDO);
eventType = DataEventTypeEnum.CREATE;
} else {
metaDataDO.setId(exist.getId());
metaDataMapper.update(metaDataDO);
eventType = DataEventTypeEnum.UPDATE;
}
// publish MetaData's event
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, eventType,
Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDO))));
}
Ici, nous avons une vue d'ensemble de MetaData(URIRegisterC'est le même principe.) Données enregistrées du service à shenyu-adminTout le processus, Vous verrez plus loin comment synchroniser les données sur la passerelle .C'est ce qui est mentionné ci - dessus.:eventPublisher.publishEvent(new DataChangedEvent .....)
shenyu-admin Synchroniser les données sur la passerelle
Au - dessuseventPublisher- Oui.ApplicationEventPublisher,C'est...spring Fonction d'écoute de publication incluse .
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.META_DATA, eventType,
Collections.singletonList(MetaDataTransfer.INSTANCE.mapToData(metaDataDO))));
// Trouver un endroit pour écouter DataChangedEventDispatcher, Les messages affichés seront onApplicationEventReçu dans la méthode
public void onApplicationEvent(final DataChangedEvent event) {
for (DataChangedListener listener : listeners) {
switch (event.getGroupKey()) {
case APP_AUTH:
listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
break;
case PLUGIN:
listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
break;
case RULE:
listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
break;
case SELECTOR:
listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
applicationContext.getBean(LoadServiceDocEntry.class).loadDocOnSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
break;
case META_DATA:
listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
break;
default:
throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
}
}
}
//listenerIl y a plusieurs classes d'implémentation, Lequel de ces
//Voyons d'abord.DataSyncConfigurationConfigurer la classe, Qui est configuré pour synchroniser les données à la passerelle
shenyu-adminDansapplication.yml Où la configuration a été trouvée :
Par défautwebsocket:
sync:
websocket:
enabled: true
messageMaxSize: 10240
# zookeeper:
# url: localhost:2181
# sessionTimeout: 5000
# connectionTimeout: 2000
# http:
# enabled: true
EtnacosAttendez....
Si ouiwebsocketEtlistenerCe qui correspondWebsocketDataChangedListener
Si ouihttpEtlistenerCe qui correspondHttpLongPollingDataChangedListener
nacosCe qui correspondNacosDataChangedListener
D'autres peuvent voir par eux - mêmes .
Si elle est basée surwebsocket,admin Sera établi avec le Service de passerelle websocketConnexion, Puis envoyez un message à la passerelle .
shenyu-adminIci.DataChangedListener Et la passerelle SyncDataServiceRéponse faciale.Par exemple,WebsocketDataChangedListener Ça correspond à la passerelle WebsocketSyncDataService.
La fonction de synchronisation des données de la passerelle est centrée sur shenyu-sync-data-centerDans le module, Il fournit également une variété de correspondances de mise en œuvre admin Comment synchroniser les données .
Est également basé sur la configuration pour voir ce qui est réellement utilisé SyncDataService.En bas.websocketConfiguration de:
@Configuration
@ConditionalOnClass(WebsocketSyncDataService.class)
@ConditionalOnProperty(prefix = "shenyu.sync.websocket", name = "urls")
Service d'appel de passerelle
À propos de la façon dont la passerelle est appelée au service , Celui - ci est principalement basé sur ShenyuWebHandler Pour traiter la demande .
Celui - ci n'a pas encore fait l'objet d'une étude plus approfondie , Préparez - vous à rester à l'arrière pour continuer à apprendre .边栏推荐
- [paper reading | deep reading] drne:deep recursive network embedding with regular equivalence
- June 24, 2022: golang multiple choice question, what does the following golang code output? A:1; B:3; C:4; D: Compilation failed. package main import ( “fmt“ ) func mai
- Five types of questions about network planning
- SystemVerilog(十三)-枚举数据类型
- 单片机进阶---PCB开发之照葫芦画瓢(二)
- Chinese translation of IMA Lazarus' the new giant, the goddess of Liberty
- Explanation and use of kotlin syntax for Android
- VW VH adaptation of mobile terminal
- How to start the phpstudy server
- Daily 3 questions (3) - check whether integers and their multiples exist
猜你喜欢

【文件包含漏洞-04】经典面试题:已知某网站仅存在本地文件包含漏洞时,如何GetShell?

【图像融合】基于形态学分析结合稀疏表征实现图像融合附matlab代码

TASK03|概率论

查询法,中断法实现USART通信

Es learning

Previous string inversion topic

Opencv learning (II) -- installing opencv on raspberry pie

MCU development -- face recognition application based on esp32-cam
![[file inclusion vulnerability-04] classic interview question: how to getshell when a website is known to have only local file inclusion vulnerability?](/img/28/ab02d38bde47053b155e0545b47039.png)
[file inclusion vulnerability-04] classic interview question: how to getshell when a website is known to have only local file inclusion vulnerability?

Open source invites you to participate in the openssf Open Source Security Online Seminar
随机推荐
撸一个随机数生成器
GaussDB 集群维护案例集-sql执行慢
Detailed explanation of Android interview notes handler
每日3题(2)- 找出数组中的幸运数
Your driver settings have been set to force 4x antialiasing in OpenGL applications
Google Earth Engine (Gee) - evaluate réalise le téléchargement en un clic de toutes les images individuelles dans la zone d'étude (certaines parties de Shanghai)
CSRF attack
金仓数据库 KingbaseES 插件identity_pwdexp
今天16:00 | 中科院计算所研究员孙晓明老师带大家走进量子的世界
炒股票开户的话,手机开户安全吗?有谁知道啊?
NETCORE performance troubleshooting
Performance memory
Android之Kotlin语法详解与使用
10.1. Oracle constraint deferred, not deferred, initially deferred and initially deferred
Previous string inversion topic
ZABBIX distributed system monitoring
A five-year technical Er, based on the real experience of these years, gives some suggestions to the fresh students
【系统分析师之路】第六章 复盘需求工程(综合知识概念)
WPF prism framework
CDN+COS搭建图床超详细步骤