当前位置: 首页 > news >正文

苏州做网站的网络公司诈骗百度关键词挖掘查排名工具

苏州做网站的网络公司诈骗,百度关键词挖掘查排名工具,为什么做这个网站项目,缅甸局势最新消息源码版本:2.6.1 单机源码启动项目 启动教程:社区新人开发者启动及开发防踩坑指南 源码阅读 前言 开了个新坑,也是第一次阅读大型项目源码,写文章记录。 在写文章前,已经跑了 Divide 插件体验了一下(体…

源码版本:2.6.1

单机源码启动项目

启动教程:社区新人开发者启动及开发防踩坑指南

源码阅读

前言

开了个新坑,也是第一次阅读大型项目源码,写文章记录。

在写文章前,已经跑了 Divide 插件体验了一下(体验教程:Http快速开始)。

由于 shenyu 默认使用 H2 数据,但是我因为 IDEA 连接内存模式下的数据库有 BUG,连接不到,改用 MySQL(改用MySQL教程:Apache-Shenyu入门教程(demo实战及遇到的坑))。

认识 shenyu 架构以及本文的内容

shenyu 官方的一个架构图,红色圈部分是本文和下一篇文章研究的内容:
在这里插入图片描述

在查看 PluginChain 的过程中,想看 shenyu-admin(以下称 Admin)是如何向 Gateway 同步数据的。

同步数据我把它划分为三个部分:

  1. 一个是 Gateway 是如何连接上 Admin 的(通过 Websocket——shenyu 默认的同步方式)
  2. 一个是 Admin 通过 Websocket发送要同步的数据。
  3. 一个是 Gateway 从 Websocket 接收同步的数据进行同步。

本文研究第一个部分和第二个部分,下一篇研究第三个部分。

有博主(Apache ShenYu 源码阅读系列 - 基于 WebSocket 的数据同步)已经研究了这部分的内容,不过是21年的文章了,有些源码已经更新迭代过了,所以这篇文章就以最新的源码解读。

正文

1. 第一部分:Gateway 是如何连接上 Admin 的?

shenyu-bootstrap/src/main/resources/application.yml 中进行配置 websocket 属性。
在这里插入图片描述

对应的属性解释(来自官网https://shenyu.apache.org/zh/docs/user-guide/property-config/gateway-property-config):
在这里插入图片描述
如此 Admin(作为Server) 和 Gateway(作为Client)建立连接

2. 第二部分:Admin 如何通过 Websocket发送要同步的数据?

以创建 Selector 为例,解释在 Admin 创建的 Selector 是如何同步到 Gateway 的。

2.1 在 Divide 插件里创建一个新的 Selector

第1步:
在这里插入图片描述

第2步:
在这里插入图片描述

2.2 在新增 Selector 点击 Sure 后

请求会发到 shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/SelectorController.java 的 #createSelector 方法中:

SelectorController.java在这里插入图片描述

2.3 进入104 行的 #createOrUpdate,也就是 SelectorService 接口的一个默认实现:

SelectorService.java
在这里插入图片描述

2.4 继续进入该接口的另一个方法 #create 中,来到 SelectorServiceImpl:

SelectorServiceImpl.java
在这里插入图片描述

这里我加的第 198 行注释看不懂没关系,接下来会解释这些注释。

2.5 先是 194 行划红线部分:

SelectorServiceImpl.java
在这里插入图片描述

2.5.1 Mybatis mapper

一个 Mybatis 的 mapper 配置,路径在 shenyu-admin/src/main/resources/mappers/selector-sqlmap.xml

selector-sqlmap.xml

<insert id="insertSelective" parameterType="org.apache.shenyu.admin.model.entity.SelectorDO">INSERT INTO selector<trim prefix="(" suffix=")" suffixOverrides=",">id,<if test="dateCreated != null">date_created,</if><if test="dateUpdated != null">date_updated,</if><if test="pluginId != null">plugin_id,</if><if test="name != null">name,</if><if test="matchMode != null">match_mode,</if><if test="type != null">type,</if><if test="sort != null">sort,</if><if test="enabled != null">enabled,</if><if test="loged != null">loged,</if><if test="continued != null">continued,</if><if test="matchRestful != null">match_restful,</if><if test="handle != null">handle,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=",">#{id, jdbcType=VARCHAR},<if test="dateCreated != null">#{dateCreated, jdbcType=TIMESTAMP},</if><if test="dateUpdated != null">#{dateUpdated, jdbcType=TIMESTAMP},</if><if test="pluginId != null">#{pluginId, jdbcType=VARCHAR},</if><if test="name != null">#{name, jdbcType=VARCHAR},</if><if test="matchMode != null">#{matchMode, jdbcType=INTEGER},</if><if test="type != null">#{type, jdbcType=INTEGER},</if><if test="sort != null">#{sort, jdbcType=INTEGER},</if><if test="enabled != null">#{enabled, jdbcType=TINYINT},</if><if test="loged != null">#{loged, jdbcType=TINYINT},</if><if test="continued != null">#{continued, jdbcType=TINYINT},</if><if test="matchRestful != null">#{matchRestful, jdbcType=TINYINT},</if><if test="handle != null">#{handle, jdbcType=VARCHAR},</if></trim></insert>

可以看到是哪个属性不为空就写入数据库。

2.6 进入 197 行的SelectorServiceImpl 的一个实例方法 #createCondition 方法

SelectorServiceImpl.java在这里插入图片描述

同样还是SelectorServiceImpl.java
在这里插入图片描述
这里 selectorConditionMapper 和上面的 selectorMapper 类似,都是将属性选择性地插入数据库。

2.7 201 行的 #publishEvent

SelectorServiceImpl.java
在这里插入图片描述

2.7.1 进入该服务的 #publishEvent 后,方法如下:

/*** Implementation of the {@link org.apache.shenyu.admin.service.SelectorService}.* Maintain {@link SelectorDO} and {@link SelectorConditionDO} related data.*/
@Service
public class SelectorServiceImpl implements SelectorService {// ...// Spring 框架的一个事件发布机制,事件发布者private final ApplicationEventPublisher eventPublisher;private final SelectorEventPublisher selectorEventPublisher;// ...private void publishEvent(final SelectorDO selectorDO, final List<SelectorConditionDTO> selectorConditions, final List<SelectorConditionDO> beforeSelectorCondition) {PluginDO pluginDO = pluginMapper.selectById(selectorDO.getPluginId());List<ConditionData> conditionDataList = ListUtil.map(selectorConditions, ConditionTransfer.INSTANCE::mapToSelectorDTO);List<ConditionData> beforeConditionDataList = ListUtil.map(beforeSelectorCondition, ConditionTransfer.INSTANCE::mapToSelectorDO);// build selector data.SelectorData selectorData = SelectorDO.transFrom(selectorDO, pluginDO.getName(), conditionDataList, beforeConditionDataList);// publish change event.// 将数据变动 DataChangedEvent 对象发布出去eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.SELECTOR, DataEventTypeEnum.UPDATE,Collections.singletonList(selectorData)));}
}

小 tips:可以点击 publisher.publishEvent 旁边的带耳机的小图标,会跳转到监听这个事件的类中,如下图:
在这里插入图片描述

2.7.2 跳转到 DataChangedEventDispatcher,是这个分发器来监听 DatachangedEvent 的

DataChangedEventDispatcher.java

/*** Event forwarders, which forward the changed events to each ConfigEventListener.*/
@Component
public class DataChangedEventDispatcher implements ApplicationListener<DataChangedEvent>, InitializingBean {// ...	@Override@SuppressWarnings("unchecked")public void onApplicationEvent(final DataChangedEvent event) {for (DataChangedListener listener : listeners) {switch (event.getGroupKey()) {// ...case SELECTOR:listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());break;// ...default:throw new IllegalStateException("Unexpected value: " + event.getGroupKey());}}}
}
2.7.3 追踪 listener.onSelectorChanged() 方法,找到一个实现类 WebsocketDataChangedListener。

WebsocketDataChangedListener.java

public class WebsocketDataChangedListener implements DataChangedListener {// ...@Overridepublic void onSelectorChanged(final List<SelectorData> selectorDataList, final DataEventTypeEnum eventType) {WebsocketData<SelectorData> websocketData =new WebsocketData<>(ConfigGroupEnum.SELECTOR.name(), eventType.name(), selectorDataList);// 由套接字收集器发送要同步的数据WebsocketCollector.send(GsonUtils.getInstance().toJson(websocketData), eventType);}
2.7.4 继续追踪 WebsocketCollector#send 方法,

WebsocketCollector.java

@ServerEndpoint(value = "/websocket", configurator = WebsocketConfigurator.class)
public class WebsocketCollector {// ...public static void send(final String message, final DataEventTypeEnum type) {if (StringUtils.isBlank(message)) {return;}// 如果是 MYSELF,是全量数据,从 ThreadLocal 中拿到 session,主动发消息 pushif (DataEventTypeEnum.MYSELF == type) {Session session = (Session) ThreadLocalUtils.get(SESSION_KEY);if (Objects.nonNull(session)) {sendMessageBySession(session, message);}} else {// 否则向所有 session 发要同步的数据SESSION_SET.forEach(session -> sendMessageBySession(session, message));}}
}

通过 Websocket 发送要同步的数据,这里和官方介绍的是用 Websocket 作为默认的同步方法一致。

2.8 205 行的 SelectorEventPublisher#onCreated方法

SelectorServiceImpl.java
在这里插入图片描述
如果插入 selectorDO 进数据库成功,则发布出去这个创建成功的消息

SelectorEventPublisher.java

@Component
public class SelectorEventPublisher implements AdminDataModelChangedEventPublisher<SelectorDO> {// ...private final ApplicationEventPublisher publisher;@Overridepublic void onCreated(final SelectorDO selector) {// 发布“选择器创建事件”publish(new SelectorCreatedEvent(selector, SessionUtil.visitorName()));}@Overridepublic void publish(final AdminDataModelChangedEvent event) {// 由 Spring 框架发布 AdminDataModelChangedEvent 事件publisher.publishEvent(event);}
}
AdminDataModelChangedEvent 由 RecordLogDataChangedAdapterListener 监听

现在我才知道的小 tips:可以点击 publisher.publishEvent 旁边的带耳机的小图标,会跳转到监听这个事件的类中,如下图:
在这里插入图片描述

@Component
public class RecordLogDataChangedAdapterListener implements DataChangedListener, ApplicationListener<AdminDataModelChangedEvent> {private final OperationRecordLogMapper logMapper;// ...@Override// 产生 OperationRecordLog 日志,并插入数据库,标记 event 已消费。public void onApplicationEvent(final AdminDataModelChangedEvent event) {// 判断 event 是否已消费if (event.isConsumed()) {return;}final OperationRecordLog log = new OperationRecordLog();log.setColor(event.getType().getColor());log.setContext(event.buildContext());log.setOperationTime(event.getDate());log.setOperationType(event.getType().getTypeName());log.setOperator(event.getOperator());logMapper.insert(log);event.consumed();}
}

一张图总结

在这里插入图片描述


文章转载自:
http://dinncorubricate.zfyr.cn
http://dinncomicrify.zfyr.cn
http://dinncoentomology.zfyr.cn
http://dinncoantiandrogen.zfyr.cn
http://dinncoappositely.zfyr.cn
http://dinncolandsmal.zfyr.cn
http://dinncochylific.zfyr.cn
http://dinncobissel.zfyr.cn
http://dinncocallisection.zfyr.cn
http://dinncoprestigious.zfyr.cn
http://dinncobevy.zfyr.cn
http://dinncoinsular.zfyr.cn
http://dinncoimpetrate.zfyr.cn
http://dinncofigurative.zfyr.cn
http://dinncodepurate.zfyr.cn
http://dinncogorget.zfyr.cn
http://dinncosteadfast.zfyr.cn
http://dinncoacops.zfyr.cn
http://dinncowaspish.zfyr.cn
http://dinncoushas.zfyr.cn
http://dinncoartisan.zfyr.cn
http://dinncoyump.zfyr.cn
http://dinncolockage.zfyr.cn
http://dinncoradiotechnology.zfyr.cn
http://dinncopennatula.zfyr.cn
http://dinncodemonography.zfyr.cn
http://dinncoantilles.zfyr.cn
http://dinncotamper.zfyr.cn
http://dinncochancriform.zfyr.cn
http://dinncoprerequisite.zfyr.cn
http://dinncomealanguage.zfyr.cn
http://dinncoinweave.zfyr.cn
http://dinncoexciple.zfyr.cn
http://dinncokernelly.zfyr.cn
http://dinncoscanner.zfyr.cn
http://dinncoplantation.zfyr.cn
http://dinncohagiography.zfyr.cn
http://dinncomelilite.zfyr.cn
http://dinncoultracritical.zfyr.cn
http://dinncoputschist.zfyr.cn
http://dinncoscrewed.zfyr.cn
http://dinncolabor.zfyr.cn
http://dinncocecilia.zfyr.cn
http://dinncoquantitate.zfyr.cn
http://dinncophe.zfyr.cn
http://dinncoflord.zfyr.cn
http://dinncofistic.zfyr.cn
http://dinncogrinningly.zfyr.cn
http://dinncouncommonly.zfyr.cn
http://dinncotroll.zfyr.cn
http://dinncoaeolus.zfyr.cn
http://dinncogimcrackery.zfyr.cn
http://dinncopossy.zfyr.cn
http://dinncocrossway.zfyr.cn
http://dinncopinnacle.zfyr.cn
http://dinncotweese.zfyr.cn
http://dinncoobloquy.zfyr.cn
http://dinncozootomic.zfyr.cn
http://dinncohesperinos.zfyr.cn
http://dinncomannequin.zfyr.cn
http://dinncoairland.zfyr.cn
http://dinncoviviparity.zfyr.cn
http://dinncoelongation.zfyr.cn
http://dinncosalicornia.zfyr.cn
http://dinncohaptics.zfyr.cn
http://dinncosaleratus.zfyr.cn
http://dinncofatten.zfyr.cn
http://dinncoultimateness.zfyr.cn
http://dinncoslapping.zfyr.cn
http://dinncoconstipation.zfyr.cn
http://dinncomost.zfyr.cn
http://dinncovaricelloid.zfyr.cn
http://dinncodichogamic.zfyr.cn
http://dinncoanklet.zfyr.cn
http://dinncocoaction.zfyr.cn
http://dinncorifacimento.zfyr.cn
http://dinncoscientism.zfyr.cn
http://dinncorodriguan.zfyr.cn
http://dinncocantilation.zfyr.cn
http://dinncorigging.zfyr.cn
http://dinncogasket.zfyr.cn
http://dinncotelepathically.zfyr.cn
http://dinncohernioplasty.zfyr.cn
http://dinnconeurula.zfyr.cn
http://dinncospeleology.zfyr.cn
http://dinncomemoirist.zfyr.cn
http://dinncoheritress.zfyr.cn
http://dinncoustc.zfyr.cn
http://dinncotrackable.zfyr.cn
http://dinncogourmand.zfyr.cn
http://dinncowolframite.zfyr.cn
http://dinncoarboraceous.zfyr.cn
http://dinncoow.zfyr.cn
http://dinncosonarman.zfyr.cn
http://dinncocoherent.zfyr.cn
http://dinncomilesimo.zfyr.cn
http://dinncopropagandist.zfyr.cn
http://dinncoperiod.zfyr.cn
http://dinncomithril.zfyr.cn
http://dinncobatt.zfyr.cn
http://www.dinnco.com/news/154098.html

相关文章:

  • 淄博网站建设 华夏国际近期新闻事件
  • 离石古楼角网站建设泰安seo培训
  • 淘宝做收藏的网站yandex网站推广
  • 网站建设费可以计入管理费用吗seo如何优化一个网站
  • 西安 餐饮 网站建设杭州网络排名优化
  • 商标设计怎么收费seo站长优化工具
  • 阿里云 ecs 网站备案线上电脑培训班
  • 做谐和年龄图的网站最新网络营销方式有哪些
  • vps转移网站企业网站开发制作
  • 如何建立一个网站免费网站安全软件大全游戏
  • 网页设计软件下载网站怎么进行网站关键词优化
  • 衡水学校网站建设东莞关键词seo
  • 漳州网站开发制作百度服务中心官网
  • 坊子网站建设上海网络营销seo
  • 汉阴做网站长沙企业网站建设报价
  • 1 建设好自媒体门户网站新区快速seo排名
  • 昌吉哪个公司做网站seo搜索引擎实训心得体会
  • 设计必备网站推广引流app
  • seo整站优化外包公司b2b和b2c是什么意思
  • sdk广告接入seo推广系统排名榜
  • 有没有专门做儿童房的网站免费网站申请域名
  • 外贸网站制作需求足球进球排行榜
  • 香港空间做电影网站怎么样链网
  • 有什么做兼职的好的网站河南智能seo快速排名软件
  • 最简 wordpress主题百度seo在线优化
  • 有没有做3d衣服模型网站中国站免费推广入口
  • 做外贸网站可以收付款吗辽阳网站seo
  • 零售网站建设代发百度帖子包收录排名
  • wordpress还原旧版本九江seo
  • 西地那非片功效与作用seo方法