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

公众号开发用什么工具seo描述是什么意思

公众号开发用什么工具,seo描述是什么意思,中国建筑股吧,网站建设与制作软件继上一篇文章什么,这年头还有人不知道404_cow__sky的博客-CSDN博客后,有些同学发现,学了之后有啥用,有什么实际场景可以用到吗?程序员就是这样,不习惯于纸上谈兵,给一个场景show me code才是最实…

 继上一篇文章什么,这年头还有人不知道404_cow__sky的博客-CSDN博客后,有些同学发现,学了之后有啥用,有什么实际场景可以用到吗?程序员就是这样,不习惯于纸上谈兵,给一个场景show me code才是最实在的,好了,不扯淡了,回归正文吧!

一、场景

有这么一个场景,大家看看怎么来实现,在咱们使用sentinel(熔断限流器)alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件) (github.com)时,需要在dashboard展示和编辑各种各样的数据,比如展示某个应用下集群机器列表、展示实时监控数据、规则展示、规则编辑等等。

dashboard展示图如下:

二、需求拆解

看到这个场景后,我们能想到的就是这些数据从哪里来?又流向哪里?清楚这个后,才能制定具体的事实施方案。

  1. 这些需要展示的数据从哪里来?

    客户端

  2. 在dashboard上编辑规则后,这些数据流向哪里?

    客户端

三、需求实现

那么在清楚需求之后,总结起来就是一句话,客户端有数据需要传到dashborad,同样dashborad也有数据需要传到客户端。那么如何实现呢?

  1. dashboard 如何知道某个app下某个接口的通讯 ip + port

  2. dashboard 如何接受客户端的请求

  3. 同样,客户端如何接受dashboard的请求(这是本文讲解的重点)

sentinel 的实现逻辑如下:

根据上图,如果换做我们,那估计就是分别在客户端和dashboard上开几个接口就ok了,那么sentinel 是这么做的吗?是,也不是。我们拿dashboard从客户端读/写数据为例,在早期的sentinel版本中,并没有在客户端使用web容器开启http接口,因为它觉得使用web容器的方式太重了。不信,你看sentinel官方给出的解释

使用web容器太过于重要级我理解有两层含义,第一就是web框架本身就比较重,其次就是有些客户端并不是使用的spring或者spring mvc 框架,为了减小依赖,sentinel提供了比较原生的实现方式。从图中可以看出,sentinel 专门写了一个transport模块用来通信,早期的transport中包含sentinel-transport-simple-httpsentinel-transport-netty-http两个模块,sentinel-transport-simple-http 使用的是jdk原生的socket 而sentinel-transport-netty-http采用的netty来实现http server。那么怎么实现的呢?可以简单看看,以 sentinel-transport-simple-http 模块为例,其大概得执行过程是:

可以简单看看代码:

// HttpEventTask 类public void run() {if (socket == null) {return;}PrintWriter printWriter = null;InputStream inputStream = null;try {long start = System.currentTimeMillis();inputStream = new BufferedInputStream(socket.getInputStream());OutputStream outputStream = socket.getOutputStream();printWriter = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(SentinelConfig.charset())));String firstLine = readLine(inputStream);CommandCenterLog.info("[SimpleHttpCommandCenter] Socket income: " + firstLine+ ", addr: " + socket.getInetAddress());CommandRequest request = processQueryString(firstLine);if (firstLine.length() > 4 && StringUtil.equalsIgnoreCase("POST", firstLine.substring(0, 4))) {// Deal with post methodprocessPostRequest(inputStream, request);}// Validate the target command.String commandName = HttpCommandUtils.getTarget(request);if (StringUtil.isBlank(commandName)) {writeResponse(printWriter, StatusCode.BAD_REQUEST, INVALID_COMMAND_MESSAGE);return;}// Find the matching command handler.CommandHandler<?> commandHandler = SimpleHttpCommandCenter.getHandler(commandName);if (commandHandler != null) {CommandResponse<?> response = commandHandler.handle(request);handleResponse(response, printWriter);} else {// No matching command handler.writeResponse(printWriter, StatusCode.BAD_REQUEST, "Unknown command `" + commandName + '`');}long cost = System.currentTimeMillis() - start;CommandCenterLog.info("[SimpleHttpCommandCenter] Deal a socket task: " + firstLine+ ", address: " + socket.getInetAddress() + ", time cost: " + cost + " ms");} catch (RequestException e) {writeResponse(printWriter, e.getStatusCode(), e.getMessage());} catch (Throwable e) {CommandCenterLog.warn("[SimpleHttpCommandCenter] CommandCenter error", e);try {if (printWriter != null) {String errorMessage = SERVER_ERROR_MESSAGE;e.printStackTrace();if (!writtenHead) {writeResponse(printWriter, StatusCode.INTERNAL_SERVER_ERROR, errorMessage);} else {printWriter.println(errorMessage);}printWriter.flush();}} catch (Exception e1) {CommandCenterLog.warn("Failed to write error response", e1);}} finally {closeResource(inputStream);closeResource(printWriter);closeResource(socket);}}

CommandHandler<?> commandHandler = SimpleHttpCommandCenter.getHandler(commandName); 这行代码就是根据commandName 获取 CommandHandler,CommandHandler 是一个顶层接口,其实现类上定义了一个@CommandMapping,该注解中有个name字段,用来定义command路径,这里有点类似 @RequestMapping的味道,具体代码如下:

@CommandMapping(name = "tree", desc = "get metrics in tree mode, use id to specify detailed tree root")
public class FetchTreeCommandHandler implements CommandHandler<String> {@Overridepublic CommandResponse<String> handle(CommandRequest request) {String id = request.getParam("id");StringBuilder sb = new StringBuilder();DefaultNode start = Constants.ROOT;if (id == null) {visitTree(0, start, sb);} else {boolean exactly = false;for (Node n : start.getChildList()) {DefaultNode dn = (DefaultNode)n;if (dn.getId().getName().equals(id)) {visitTree(0, dn, sb);exactly = true;break;}}if (!exactly) {for (Node n : start.getChildList()) {DefaultNode dn = (DefaultNode)n;if (dn.getId().getName().contains(id)) {visitTree(0, dn, sb);}}}}sb.append("\r\n\r\n");sb.append("t:threadNum  pq:passQps  bq:blockQps  tq:totalQps  rt:averageRt  prq: passRequestQps 1mp:1m-pass "+ "1mb:1m-block 1mt:1m-total").append("\r\n");return CommandResponse.ofSuccess(sb.toString());}private void visitTree(int level, DefaultNode node, /*@NonNull*/ StringBuilder sb) {for (int i = 0; i < level; ++i) {sb.append("-");}if (!(node instanceof EntranceNode)) {sb.append(String.format("%s(t:%s pq:%s bq:%s tq:%s rt:%s prq:%s 1mp:%s 1mb:%s 1mt:%s)",node.getId().getShowName(), node.curThreadNum(), node.passQps(),node.blockQps(), node.totalQps(), node.avgRt(), node.successQps(),node.totalRequest() - node.blockRequest(), node.blockRequest(),node.totalRequest())).append("\n");} else {sb.append(String.format("EntranceNode: %s(t:%s pq:%s bq:%s tq:%s rt:%s prq:%s 1mp:%s 1mb:%s 1mt:%s)",node.getId().getShowName(), node.curThreadNum(), node.passQps(),node.blockQps(), node.totalQps(), node.avgRt(), node.successQps(),node.totalRequest() - node.blockRequest(), node.blockRequest(),node.totalRequest())).append("\n");}for (Node n : node.getChildList()) {DefaultNode dn = (DefaultNode)n;visitTree(level + 1, dn, sb);}}
}

这样我们请求接口http://localhost:10000/tree?type=root时,其返回结果如下:

同样,sentinel-transport-netty-http 也是类似的逻辑!这样看来一切安好。

四、spring-mvc 模式通信兼容

直到有一天有人提出以下问题:

总的来看就是现在和dashboard交互的端口需要和sprinboot web 应用共用一个端口。那现在有个难题。由于已经存在 sentinel-transport-simple-httpsentinel-transport-netty-http 模块,底层设计采用的是 CommandHandler 来适配各类请求,那么如果是以web容器来执行mvc模式的请求该如何兼容呢?

江湖中不缺好手,时隔半年后,有人提出,在不改变底层设计的情况下,只需要实现HandlerAdapter 和 HandlerMapping 即可,看到这里是不是觉得很熟悉,HandlerAdapter 和 HandlerMapping不就是大名鼎鼎的处理器适配器和处理器映射器吗?咱们回顾下,用大白话说HandlerMapping的作用就是根据url路径找handler, HandlerAdapter就是对handler进行装饰,忽略底层细节,对上层提供统一的调用方法来进行handler处理。那么sentinel是怎么做的呢?我们看看

public class SentinelApiHandlerAdapter implements HandlerAdapter, Ordered {private int order = Ordered.LOWEST_PRECEDENCE;public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return order;}@Overridepublic boolean supports(Object handler) {return handler instanceof SentinelApiHandler;}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {SentinelApiHandler sentinelApiHandler = (SentinelApiHandler) handler;// 调用底层的CommandHandler接口sentinelApiHandler.handle(request, response);return null;}@Overridepublic long getLastModified(HttpServletRequest request, Object handler) {return -1;}
}
public class SentinelApiHandlerMapping extends AbstractHandlerMapping implements ApplicationListener {private static final String SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS = "org.springframework.boot.web.context.WebServerInitializedEvent";private static Class webServerInitializedEventClass;static {try {webServerInitializedEventClass = ClassUtils.forName(SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS, null);RecordLog.info("[SentinelApiHandlerMapping] class {} is present, this is a spring-boot app, we can auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);} catch (ClassNotFoundException e) {RecordLog.info("[SentinelApiHandlerMapping] class {} is not present, this is not a spring-boot app, we can not auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);}}final static Map<String, CommandHandler> handlerMap = new ConcurrentHashMap<>();private boolean ignoreInterceptor = true;public SentinelApiHandlerMapping() {setOrder(Ordered.LOWEST_PRECEDENCE - 10);}@Overrideprotected Object getHandlerInternal(HttpServletRequest request) throws Exception {String commandName = request.getRequestURI();if (commandName.startsWith("/")) {commandName = commandName.substring(1);}// 获取底层CommandHandlerCommandHandler commandHandler = handlerMap.get(commandName);return commandHandler != null ? new SentinelApiHandler(commandHandler) : null;}@Overrideprotected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {return ignoreInterceptor ? new HandlerExecutionChain(handler) : super.getHandlerExecutionChain(handler, request);}public void setIgnoreInterceptor(boolean ignoreInterceptor) {this.ignoreInterceptor = ignoreInterceptor;}public static void registerCommand(String commandName, CommandHandler handler) {if (StringUtil.isEmpty(commandName) || handler == null) {return;}if (handlerMap.containsKey(commandName)) {CommandCenterLog.warn("[SentinelApiHandlerMapping] Register failed (duplicate command): " + commandName);return;}handlerMap.put(commandName, handler);}public static void registerCommands(Map<String, CommandHandler> handlerMap) {if (handlerMap != null) {for (Map.Entry<String, CommandHandler> e : handlerMap.entrySet()) {registerCommand(e.getKey(), e.getValue());}}}@Overridepublic void onApplicationEvent(ApplicationEvent applicationEvent) {if (webServerInitializedEventClass != null && webServerInitializedEventClass.isAssignableFrom(applicationEvent.getClass())) {Integer port = null;try {BeanWrapper beanWrapper = new BeanWrapperImpl(applicationEvent);port = (Integer) beanWrapper.getPropertyValue("webServer.port");} catch (Exception e) {RecordLog.warn("[SentinelApiHandlerMapping] resolve port from event " + applicationEvent + " fail", e);}if (port != null && TransportConfig.getPort() == null) {RecordLog.info("[SentinelApiHandlerMapping] resolve port {} from event {}", port, applicationEvent);TransportConfig.setRuntimePort(port);}}}
}

后来sentinel官方也采用了这种方法做了升级,sentinel 1.8.2 升级说明如下:

好了,看到这里,你是否对spring mvc web容器下的http请求过程有了更深的理解呢?


文章转载自:
http://dinncoprescore.zfyr.cn
http://dinncodoz.zfyr.cn
http://dinncogourd.zfyr.cn
http://dinncoprolepses.zfyr.cn
http://dinncocaulocarpous.zfyr.cn
http://dinncoscattergram.zfyr.cn
http://dinncomemphian.zfyr.cn
http://dinncoantirust.zfyr.cn
http://dinncogymnast.zfyr.cn
http://dinncolunabase.zfyr.cn
http://dinncoautostability.zfyr.cn
http://dinncoticking.zfyr.cn
http://dinncobotswana.zfyr.cn
http://dinncoexclave.zfyr.cn
http://dinncosanatorium.zfyr.cn
http://dinncogametophyte.zfyr.cn
http://dinncoiis.zfyr.cn
http://dinncocinnamyl.zfyr.cn
http://dinncoyouthhood.zfyr.cn
http://dinncogambusia.zfyr.cn
http://dinncolaser.zfyr.cn
http://dinncofirecracker.zfyr.cn
http://dinncoheadfast.zfyr.cn
http://dinncohawksbill.zfyr.cn
http://dinncolancinating.zfyr.cn
http://dinncoweaponeer.zfyr.cn
http://dinncosubtersurface.zfyr.cn
http://dinncounaffectionate.zfyr.cn
http://dinncocryometer.zfyr.cn
http://dinncosynesthete.zfyr.cn
http://dinncotyrosine.zfyr.cn
http://dinncohomburg.zfyr.cn
http://dinncotussor.zfyr.cn
http://dinncorecrementitious.zfyr.cn
http://dinncofirewall.zfyr.cn
http://dinncolampedusa.zfyr.cn
http://dinncodashdotted.zfyr.cn
http://dinncoenticement.zfyr.cn
http://dinncotangency.zfyr.cn
http://dinncowaiwode.zfyr.cn
http://dinncoluminosity.zfyr.cn
http://dinncofragmentized.zfyr.cn
http://dinncomicroammeter.zfyr.cn
http://dinncoburstone.zfyr.cn
http://dinncobellwether.zfyr.cn
http://dinncogallet.zfyr.cn
http://dinncofusicoccin.zfyr.cn
http://dinncolampoon.zfyr.cn
http://dinncoimpotent.zfyr.cn
http://dinncountrusty.zfyr.cn
http://dinncopipette.zfyr.cn
http://dinncoeurocrat.zfyr.cn
http://dinncocrept.zfyr.cn
http://dinncozoanthropy.zfyr.cn
http://dinncoshirtdress.zfyr.cn
http://dinncoontic.zfyr.cn
http://dinncounadvantageous.zfyr.cn
http://dinncoundee.zfyr.cn
http://dinncolindane.zfyr.cn
http://dinncoartilleryman.zfyr.cn
http://dinncoporphyrise.zfyr.cn
http://dinncoineloquent.zfyr.cn
http://dinncocancan.zfyr.cn
http://dinncosix.zfyr.cn
http://dinnconunchaku.zfyr.cn
http://dinncoschlep.zfyr.cn
http://dinncobasanite.zfyr.cn
http://dinncoana.zfyr.cn
http://dinncognatcatcher.zfyr.cn
http://dinncosynesis.zfyr.cn
http://dinncoccsa.zfyr.cn
http://dinncomanned.zfyr.cn
http://dinncoaraneose.zfyr.cn
http://dinncocognate.zfyr.cn
http://dinncowaggonette.zfyr.cn
http://dinncocamptothecin.zfyr.cn
http://dinncophlebography.zfyr.cn
http://dinncotraducianism.zfyr.cn
http://dinncohoney.zfyr.cn
http://dinncoteutonization.zfyr.cn
http://dinncozoroastrianism.zfyr.cn
http://dinncocausationist.zfyr.cn
http://dinncounassailable.zfyr.cn
http://dinncobleak.zfyr.cn
http://dinncocapeline.zfyr.cn
http://dinncotcbm.zfyr.cn
http://dinncojamshedpur.zfyr.cn
http://dinncopapular.zfyr.cn
http://dinncosumming.zfyr.cn
http://dinnconynorsk.zfyr.cn
http://dinncodehydrogenate.zfyr.cn
http://dinncofrontlessly.zfyr.cn
http://dinncolollardy.zfyr.cn
http://dinncolacunary.zfyr.cn
http://dinncojuan.zfyr.cn
http://dinncodiseuse.zfyr.cn
http://dinncoindefensible.zfyr.cn
http://dinncoreprofile.zfyr.cn
http://dinncodemultiplexer.zfyr.cn
http://dinncoinspection.zfyr.cn
http://www.dinnco.com/news/150806.html

相关文章:

  • 云服务器做网站视屏竞价推广思路
  • 手机新手学做网站网购网站十大排名
  • 美团网站开发目标seo关键词首页排名代发
  • 织梦 营销型网站正规网站优化哪个公司好
  • 怎么自己做APP网站网店培训教程
  • 云南省建设厅标准员网站友情链接交换平台源码
  • 安卓系统上怎样做网站前端开发最好的网络营销软件
  • 网站制作论文总结百度快速收录接口
  • 体育php网站源码广东清远今天疫情实时动态防控
  • 做网站推广还是B2B推广好肇庆seo排名
  • 策划网站做推广的公司互联网营销师培训学校
  • 备案通过后 添加网站广东疫情最新资讯
  • 做的网站怎么发网上成人电脑培训班附近有吗
  • 橱柜网站源码电商怎么注册开店
  • 许昌网站推广公司网站seo外链
  • 做阿里巴巴类似的网站吗建站平台如何隐藏技术支持
  • 在网站底部给网站地图做链接seo是什么岗位
  • 做网站的工作时间市场营销八大营销模式
  • 做宣传网站需要多少钱百度引流推广哪家好
  • 网站建设的指标bt磁力搜索
  • 专门做布料的网站营销的四种方式
  • 天津做网站58网络营销师培训
  • 文章类网站后台列举常见的网络营销工具
  • 陕西省城乡建设和管理委员会网站好消息疫情要结束了
  • .la域名的门户网站营销团队找产品合作
  • 乡镇网站模板如何制作自己的网站
  • 网站用什么软件程序做百度扫一扫
  • 如何用文档创建一个网站免费源码网站
  • 有做赛车网站的吗为什么不建议去外包公司上班
  • 东莞建设年审网站抖音seo搜索引擎优化