首页 文章 精选 留言 我的

精选列表

搜索[AI教育],共10000篇文章
优秀的个人博客,低调大师

【熵增教育】Anders-SpringBoot中的Http应用:WebFlux——熵增学院

我们今天开始进入Spring WebFlux.WebFlux是Spring5.0开始引入的.有别于SpringMVC的Servlet实现,它是完全支持异步和非阻塞的.在正式使用Spring WebFlux之前,我们首先得了解他和Servlet的区别,以及他们各自的优势,这样我们才能够给合适的场景选择合适的开发工具. 首先我们要问几个问题,为什么要有异步?在异步之前,软件行业做过哪些努力,他们的优势是什么?基于这几个问题,我们今天分享以下三个知识点: 从Http1.X 到Http2.0 从Servlet2.x到Servlet3.x WebFlux的出场 1. 从Http1.x到Http2.0 异步和同步是无法分开的.他们对性能的理解和处理也是各有千秋.传统的web项目因为是基于阻塞I/O模型而建立的,所以他们只能通过对整个链路的优化来提升性能,而这里的性能就包括了伸缩性和响应速度.这里面比较重要的一个环节就是网络传输.相对而言,这也是距离我们的用户最近的一个环节,因此他们对并发的处理以及对响应速度的处理就比其他的会更直接地影响我们的用户. 1.1 Http/1.x 在http1.x中,我们都知道,http会先进行三次握手,握手成功之后,开始传递数据,服务器响应完毕,就进行四次挥手,最后关闭链接.刚开始应用这个概念的时候,是非常受欢迎的,因为在那时候传递的还是静态页面或者动态数据比较少的资源,因此无论是客户端还是服务器端,他都节省了更多的资源.但随着互联网的飞速发展,这种方式就遇到了问题.如果每次传递数据都需要三次握手四次挥手的话,那么随着数据访问量的增加,那么三次握手四次挥手带来的资源消耗就会成为影响系统的瓶颈.这就好像一根针重量可以忽略,但当我们聚集上亿根针的时候,那么他的重量和所占用的空间,就成了必须要考虑的问题了. 那能不能建立好一次链接之后,我多传递几次数据,然后在关闭呢?当然可以,这就是长链接,也就是大家常说的"Keep-Alive".而HTTP1.1则是默认就开启了Keep-Alive.Keep-Alive虽然暂时性的解决了建立链接所带来的开销,也一定程度的提高了响应速度,但后来又凸显了另外两个问题: 首先,因为http是串行文件传输.所以当客户端请求a文件时,b文件只能等待.等待a链接到服务器,服务器处理文件,服务器返回文件这三个步骤完成后,b才能接着处理.我们假设,链接服务器,服务器处理,服务器返回各需要1秒,那么b处理完的时候就需要6秒,以此类推.(当然,这里有个前提,服务器和浏览器都是单通道的.)这就是我们说的阻塞. 其次,链接数的问题.我们都知道服务器的链接数是有限的.并且浏览器也对链接数有限制.这样能接入进来的服务就是有个数限制的,当达到这个限制的时候,其他的就需要等待链接被断开,然后新的请求才能够进入.这个比较容易理解. 之所以http1.x会使用串行文件传输,是因为http传输的无论是request还是response都是基于文本的,所以接收端无法知道数据的顺序,因此必须按着顺序传输.这也就限制了只要请求就必须新建立一个链接,这也就导致了第二个问题的出现. 1.2 Http/2 为了从根本上行解决http1.x所遗留的这两个问题,http2引入了二进制数据帧和流的概念.其中帧的作用就是对数据进行顺序标识,这样的话,接收端就可以根据顺序标识来进行数据合并了.同时,因为数据有了顺序,服务器和客户端就可以并行的传输数据,而这就是流所作的事情. 这样,因为服务器和客户端可以借助流进行并行的传递数据,那么同一台客户端就可以使用一个链接来进行传输,此时服务器能处理的并发数就有了质的飞跃. http/2的这个新特性,就是多路复用.我们可以看到,多路复用的本质就是并行传输.那web对请求的处理是否可以使用这个思路呢? 2.Servlet 现在我们来讨论Servlet与Netty.这两个一个主要是以同步阻塞的方式服务的,另一个是异步非阻塞的.这也就造成了他们适用的场景是不同的. 2.1 Servlet 做JavaWeb研发的几乎没有不知道Servlet的.在Servlet 3.0之前,Servlet采用Thread-Per-Request的方式处理请求,即每一次Http请求都由某一个线程从头到尾负责处理。如果一个请求需要进行IO操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待IO操作完成, 而IO操作是非常慢的,所以此时的线程并不能及时地释放回线程池以供后续使用,在并发量越来越大的情况下,这将带来严重的性能问题。为了解决这一的问题,Servlet3.0引入了异步处理. 在Servlet 3.0中,我们可以从HttpServletRequest对象中获得一个AsyncContext对象,该对象构成了异步处理的上下文,Request和Response对象都可从中获取。AsyncContext可以从当前线程传给另外的线程,并在新的线程中完成对请求的处理并返回结果给客户端,初始线程便可以还回给容器线程池以处理更多的请求。如此,通过将请求从一个线程传给另一个线程处理的过程便构成了Servlet 3.0中的异步处理。 这里举个例子,对于一个需要完成长时处理的Servlet来说,其实现通常为: packagetop.lianmengtu.testjson.servlet; importjavax.servlet.ServletException; importjavax.servlet.annotation.WebServlet; importjavax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; //@WebServlet("/syncHello"),因为使用的SpringBoot模拟,所以注释掉该注解 publicclassMyServletextendsHttpServlet{ @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{ super.doGet(req,resp); newLongRunningProcess().run(); System.out.println("HelloWorld"); } } LongRunningProcess实现如下: packagetop.lianmengtu.testjson.servlet; importjava.util.concurrent.ThreadLocalRandom; publicclassLongRunningProcess{ publicvoidrun(){ try{ intmillis=ThreadLocalRandom.current().nextInt(2000); StringcurrentThread=Thread.currentThread().getName(); System.out.println(currentThread+"sleepfor"+millis+"milliseconds."); Thread.sleep(millis); }catch(InterruptedExceptione){ e.printStackTrace(); } } } 我们现在将MyServlet注入到Spring容器中: @Bean publicServletRegistrationBeanservletRegistrationBean(){ returnnewServletRegistrationBean(newMyServlet(),"/syncHello"); } 此时的SyncHelloServlet将顺序地先执行LongRunningProcess的run()方法,然后在控制台打印HelloWorld.而3.0则提供了对异步的支持,因此在Servlet3.0中我们可以这么写: @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{ AsyncContextasyncContext=req.startAsync(); asyncContext.start(()->{ newLongRunningProcess().run(); try{ asyncContext.getResponse().getWriter().print("HelloWorld"); }catch(IOExceptione){ e.printStackTrace(); } asyncContext.complete(); }); } 此时,我们先通过request.startAsync()获取到该请求对应的AsyncContext,然后调用AsyncContext的start()方法进行异步处理,处理完毕后需要调用complete()方法告知Servlet容器。start()方法会向Servlet容器另外申请一个新的线程(可以是从Servlet容器中已有的主线程池获取,也可以另外维护一个线程池,不同容器实现可能不一样),然后在这个新的线程中继续处理请求,而原先的线程将被回收到主线程池中。事实上,这种方式对性能的改进不大,因为如果新的线程和初始线程共享同一个线程池的话,相当于闲置下了一个线程,但同时又占用了另一个线程。 Servlet 3.0对请求的处理虽然是异步的,但是对InputStream和OutputStream的IO操作却依然是阻塞的,对于数据量大的请求体或者返回体,阻塞IO也将导致不必要的等待。因此在Servlet 3.1中引入了非阻塞IO,通过在HttpServletRequest和HttpServletResponse中分别添加ReadListener和WriterListener方式,只有在IO数据满足一定条件时(比如数据准备好时),才进行后续的操作。 虽然Servlet3.1提供了异步的方式,并且做的也比Servlet3.0更彻底,但是如果我们使用了Servlet3.1提供的异步接口,像刚刚的代码演示的那样,那么我们在之后的处理中就没有办法再使用他原来的接口了.这就让我们处于了一种非此即彼的状况中.如果是这样,Servlet系列的技术,如SpringMVC也就是这样了.那怎么办呢? 3. WebFlux的出场 现在我们会从以下几个层面来探讨WebFlux 为什么要有WebFlux? Reactive定义与ReactiveAPI WebFlux中的性能问题 WebFlux的并发模型 WebFlux的适用性 3.1为什么要有WebFlux 首先,为什么要有webFlux? 在前面两部分,我们一直在探讨并发问题.为了解决并发,我们需要使用非阻塞的web技术栈.因为非阻塞的web栈使用的线程数更少,对硬件资源的要求更低.虽然Servlet3.1为非阻塞I/O提供了一些支持,但刚刚我们提到了,如果我们使用Servlet3.1里的非阻塞API,会导致我们无法再使用它原来的API.并且,自从非阻塞I/O以及异步概念出现之后,就诞生了一批专为异步和非阻塞I/O设计的服务器,比如Netty,这就催生了新的能服务于各种非阻塞I/O服务器的统一的API. WebFlux诞生的另一个重要原因是函数式程序设计.随着脚本型语言(Nodejs,Angular等)的扩张,函数式程序设计以及后继式API也相继火起来.以至于Java也在Java8中引入了Lambda来对函数式程序设计进行支持,又引入了StreamAPI来对后继式程序进行支持.由此,对具备函数式编程和后继式程序设计的Web框架的需求也越来越大了。 3.2Reactive的定义与API Reactive的定义 我们接触了"非阻塞"和"函数式",那reactive是什么意思呢? "reactive"这个术语指的是:围绕着对改变做出响应的程序设计模型---网络组件对IO事件做出响应,UIController对鼠标事件做出响应等等.在那种情况下,非阻塞取代了阻塞是响应式的,我们正处于响应模式中,当操作完成和数据变得可用的时候发起通知. 还有另一个重要的机制那就是我们在spring team里整合"reactive"以及非阻塞式背压机制.在同步里,命令式的代码,阻塞式地调用服务为普通的表单充当背压机制强迫调用者等待.在非阻塞式编程中,控制事件的频率就变得很重要防止快速的生产者不会压垮他的目的地. Reactive Streams 是一个定义了使用背压机制的异步组件之间交互设计的小型说明书(在Java9中也采纳了).例如,一个数据仓库(可以看做Publisher)可以生产数据,然后HTTP Server(看做订阅者)可以写入到响应里.Reactive Streams的主要目的是让订阅者可以控制生产者产生数据的速度有多快或有多慢. Reactive API Reactive Streams 在互操作性上扮演了一个很重要的角色.类库和基础设施组件虽然有趣,但对于应用程序API来说却用处甚少,因为他们太底层了.应用程序需要一个更高级别更丰富的函数式API来编写异步逻辑---和Java8里的StreamAPI很类似,不过不仅仅是为集合做准备的. Reactor 是为SpringWebFlux选择的一个reactive类库.它提供了Mono和Flux类型的API来处理0..1(Mono)和0..N(Flux)数据序列化通过一组丰富的操作集和ReactiveX vocabulary of operators对齐.Reactor 是一个Reactive Streams类库,所以他所有的操作都支持非阻塞背压机制.Reactor强烈地聚焦于Server端的Java.他在发展上和Spring有着紧密的协作. WebFlux要求Reactor作为一个核心依赖,但凭借Reactive Streams也可以和其他的reactive libraries一起使用.一般来说,一个WebFlux API 接收一个Publisher作为输入,转换给一个内置的Reactor类型来使用,最后返回一个Flux或一个Mono作为输出.所以,你可以批准任何的Publisher作为输入,你可以应用操作在输出上,但你因为你使用了其他的reactive library所以你需要进行转换.只要可行(例如,注解controllers),WebFlux可以在使用RXJava和另一个reactive library之间透明的改变.看Reactive Libraries获取更多地细节. 3.3 性能 性能这个词有很多特征和含义.Reactive 和非阻塞通常不会使应用程序运行地更快.在某些场景下,他们也可以.(例如,在并行条件下使用WebClient来执行远程调用的话).整体来说,非阻塞方式可能需要做更多的工作并且他也会稍微增加请求处理的时间. 对reactive和非阻塞好处的预期关键在于使用小,固定的线程数和更少的内存来扩展的能力.这使应用程序在加载的时候更加有弹性,因为他们以一种更可以预测的方式扩展.然而为了看到这些好处,你需要一些延迟(包括比较慢的不可预知的网络I/O).那是响应式堆栈开始显示他力量的地方,并且这些不同是非常吸引人的. 3.4并发模型 Spring MVC和Spring WebFlux都支持注解Controllers,但他们在并发模型和对阻塞和线程的默认呈现(assumptions)上是非常不同的.在Spring MVC(和通用的servlet应用)中,都假设应用程序是阻塞当前线程的(例如,远程调用),并且出于这个原因,servlet容器处理请求的期间使用一个巨大的线程池来吸收潜在的阻塞. 在Spring WebFlux(和非阻塞服务器)中,假设应用程序是非阻塞的,所以,非阻塞服务器使用小的,固定代销的线程池(event loop workders)来处理请求. "弹性伸缩"和"小数量的线程"或许听起来矛盾,但是对于不会阻塞当前线程(用依赖回调来取代)意味着你不需要额外的线程,因为非阻塞调用给处理了. 调用一个阻塞API 要是你需要使用阻塞库怎么办?Reactor和RxJava都提供了publishOn操作用一个不同的线程来继续处理.那意味着有一个简单的脱离舱口(一个可以离开非阻塞的出口).然而,请牢记,阻塞API对于并发模型来说不太合适. 易变的状态 在Reactor和RxJava里,你通过操作符生命逻辑,在运行时在不同的阶段里,都会形成一个进行数据序列化处理的管道.这样做的一个主要好处就是把应用程序从不同的状态保护中解放了出来,因为管道中的应用代码是绝不会被同时调用的. 线程模型 在运行了一个使用Spring WebFlux的服务器上,你期望看到什么线程呢? 在一个"vanilla"Spring WebFlux服务器上(例如,没有数据访问也没有其他可选的依赖),你能够看到一个服务器线程和几个其他的用来处理请求的线程(一般来说,线程的数目和CPU的核数是一样的).然而,Servlet容器在启动的时候就使用了更多的线程(例如,tomcat是10个),来支持servlet(阻塞)I/O和servlet3.1(非阻塞)I/O的用法. 响应式的WebClient操作是用Event Loop方式.所以你可以看到少量的固定数量的线程和他关联.(例如,使用了Reactor Netty连接的reactor-http-nio).然而,如果Reactor Netty在客户端和服务端都被使用了,这两者之间的event loop资源默认是被共享的. Reactor和RxJava提供了抽象化的线程池,调度器目的是结合publishOn操作符在不同的线程池之间切换操作.调度器有一个名字,建议这个名字是一个具体的并发策略--例如,"parallel"(因为CPU-bound使用有限的线程数来工作)或者"elastic"(因为I/O-bound使用大量的线程来工作).如果你看到这类的线程,这就意味着一些代码正在使用一个具体的使用了Scheduler策略的线程池. 数据访问库和其他第三方库依赖也创建和使用了他们自己的线程. 下次我们来分享Spring WebFlux的使用. 本文相关视频

优秀的个人博客,低调大师

马云纽约演讲全文:再不改革教育,年轻人都要失业

作者:造就 来源:造就(ID:xingshu100) 编者按:2017年9月20日,阿里巴巴集团董事局主席马云在彭博世界经济论坛上发表演讲。以下为演讲全文。 马云: 克林顿总统先生、迈克尔、各位阁下、朋友们,早上好。 先前他们联系我说,纽约有一场论坛,让我们分享对未来的想法和思考。我感到非常兴奋和荣幸。 我不是政治家,也不是科学家。我是个商人。作为一名企业家,我非常高兴地在此分享我们从生活中学到了什么,我们应该以怎样的态度面对未来。 作为一名企业家,我们非常清楚地知道,如果我们失去领导力,失去想象力,我们的公司将没有前途。在我的公司还非常小的时候,我们每天都寻找机会壮大自己。现在,我的公司变得很大,我每天都担心有什么其他的风险,有什么其他的事情将阻碍我们前进,变成公司的毒瘤。 我们在摸清这些问题时,必须思考一件事:该如何把这些问题转化成机遇?在这

优秀的个人博客,低调大师

xzs-mysql v3.8.0 发布,Java 跨平台在线教育考试系统

学之思简介: 学之思开源考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷、界面设计友好、代码结构清晰。支持 web 端和微信小程序,能覆盖到 pc 机和手机等设备。 支持多种部署方式:集成部署、前后端分离部署、docker 部署。 本次更新内容: 1. 升级前端node版本至16,兼容v12-v16 2. 升级element ui框架版本 3. 修复element ui兼容性问题 4. 修复微信小程序兼容问题 5. 修复部分系统登录失败问题 6. 接口、教程文档更新 学生端功能: 模块 介绍 登录 用户名、密码 注册 年级、用户名、密码 任务中心 管理员发布的年级任务,每个学生只能做一次 考试 题干支持文本、图片、数学公式、表格等,学生答题支持:文本 固定试卷 可重复练习、自行批改的试卷 时段试卷 在时间限制内,可重复练习、自行批改的试卷 考试记录 查看答卷记录和试卷信息 错题本 答错题目会自动进入错题本,显示题目基本信息 个人信息 显示学生个人资料 更新信息 修改个人资料、头像 个人动态 显示用户最近的个人动态 消息中心 用于接收管理员发送的消息 管理端功能: 模块 介绍 登录 用户名、密码 主页 试卷总数、题目总数、用户活跃度、题目月数量 学生列表 显示系统所有的学生,新增、修改、删除、禁用 管理员列表 显示系统所有的管理员,新增、修改、删除、禁用 学科列表 学科查询、修改、删除 学科创编 创建学科 试卷列表 试卷查询、修改、删除 试卷创编 创建的试卷为时段试卷、固定试卷、任务试卷 题目列表 题目查询、修改、删除 题目创建 题目支持单选题、多选题、判断题、填空题、简答题,题干支持文本、图片、表格、数学公式 任务列表 任务查询、修改、删除 消息列表 显示已发送的消息,消息已读人数等信息 消息发送 发送消息给多个用户 用户日志 显示所有用户日志 个人资料 显示管理员用户名、真实姓名 时间线 显示管理员创建时间 修改资料 修改姓名、手机号 小程序功能: 模块 介绍 登录 用户登录登出功能,登录会自动绑定微信账号,登出会解绑 注册 年级、用户名、密码 任务中心 管理员发布的年级任务,每个学生只能做一次 考试 题干支持文本、图片、数学公式、表格等,学生答题支持:文本 固定试卷 可重复练习、自行批改的试卷 时段试卷 在时间限制内,可重复练习、自行批改的试卷 考试记录 查看答卷记录和试卷信息 错题本 答错题目会自动进入错题本,显示题目基本信息 个人信息 显示学生个人资料 更新信息 修改个人资料、头像 个人动态 显示用户最近的个人动态 消息中心 用于接收管理员发送的消息

优秀的个人博客,低调大师

xzs-wechat v1.0.0 发布,小程序在线教育系统

项目简介: xzs-wechat 是一款微信小程序考试系统,可用于考试小程序、答题小程序、毕业设计小程序,有前后端源码和数据库。有完整的文档教程和视频教程,易于二次开发,部署简单快捷、界面设计友好。 本次更新内容: 1. 修复iView下拉框不兼容问题 2. 修复微信绑定token报错 3. 升级iView版本 4. 修复试卷列表无数据,看不到暂无提示框 5. 文档教程更新 功能简介: 登录:用户输入用户名和密码,进行登录,会自动和微信账户进行绑定,下次面登录 注册:用户输入年级、用户名、密码可完成注册 任务中心:管理员发布任务试卷,用户可以完成对应的任务 考试:管理员发布试卷,用户可完成试卷,题干支持文本、图片、数学公式、表格等 固定试卷:可重复练习、自行批改的试卷 时段试卷:在时间限制内,可重复练习、自行批改的试卷 考试记录:展示用户所有的答卷记录 错题本:试卷中答错题目会自动进入错题本,展示题目基本信息 个人信息:展示用户的基本信息 更新信息:修改个人资料、头像 个人动态:展示用户最近操作的日志 消息中心:展示管理员发布的所有消息

优秀的个人博客,低调大师

学之思教育考试系统 2.0.2 发布:前后端分离、多平台考试系统

项目介绍 学之思在线考试系统是一款 java + vue 的前后端分离的考试系统。主要优点是开发、部署简单快捷,可水平拓展在多台服务器上做负载均衡。考试功能齐全,目前有web端和微信小程序,能覆盖到pc机和手机等设备。 v2.0.2更新内容: 1.修复了串用户的bug 2.新增头像上传和修改 3.修复缓存为null的bug 4.优化题目创建光标 6.新增学科删除bug 7.文件存储有原来的fdfs修改为七牛云 8.代码优化和更新等

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册