当前位置:网站首页>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 .
边栏推荐
- Android之Kotlin语法详解与使用
- 网络远程访问的方式使用树莓派
- After reading this article, I will teach you to play with the penetration test target vulnhub - drivetingblues-7
- CSRF attack
- 【观察】ObjectScale:重新定义下一代对象存储,戴尔科技的重构与创新
- Sign up to open the third session of the "flying oar hacker marathon". It's been a long time
- WPF binding expression and binding data source (I)
- GaussDB 如何统计用户sql的响应时间
- Detailed explanation of Android interview notes handler
- 報名開啟|飛槳黑客馬拉松第三期如約而至,久等啦
猜你喜欢
Use of Siemens plcs7-200 (I) -- Introduction to development environment and configuration software
Socket communication principle
scrapy+scrapyd+gerapy 爬虫调度框架
报名开启|飞桨黑客马拉松第三期如约而至,久等啦
NuxtJS实战案例
Coscon'22 lecturer solicitation order
垃圾回收机制
Software testing to avoid being dismissed during the probation period
戴尔科技演绎“快”字诀,玩转CI/CD
OpenCV学习(一)---环境搭建
随机推荐
手机办理长投学堂证券开户靠谱安全吗?
输出式阅读法:把学到的知识用起来
COSCon'22 讲师征集令
A random number generator
无心剑中译伊玛·拉扎罗斯《新巨人·自由女神》
持续交付-Jenkinsfile 语法
2022年PMP项目管理考试敏捷知识点(2)
【文件包含漏洞-04】经典面试题:已知某网站仅存在本地文件包含漏洞时,如何GetShell?
3 Questions par jour (3) - vérifier l'existence d'entiers et de leurs doubles
Performance network
开源社邀请您参加OpenSSF开源安全线上研讨会
金仓数据库 KingbaseES 插件DBMS_RANDOM
[image fusion] image fusion based on morphological analysis and sparse representation with matlab code
性能之文件系统篇
After reading this article, I will teach you to play with the penetration test target vulnhub - drivetingblues-7
ES 学习
報名開啟|飛槳黑客馬拉松第三期如約而至,久等啦
VW VH adaptation of mobile terminal
Checking whether the double value is an integer - Swift - checking if a double value is an integer - swift
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)