在阅读完back-center源码后,是否注意过,咱们的pom依赖中引用了spring-boot-starter-web,定义了server.port ,同时定义了静态资源,那么这个starter究竟干了什么事情。 ## 回顾back-center中的代码 * 启动端口 ![](https://img.kancloud.cn/e9/a0/e9a030ab2d3d10442271c56ff875abc6_1148x169.png) * 前端代码 ![](https://img.kancloud.cn/85/10/8510afed3cf80a7360258f3552c6de27_1638x768.png) ## server.port ![](https://img.kancloud.cn/de/2e/de2e038b95ae1ddf46b60b27fb7a4539_1742x737.png) * 咱们阅读springboot 代码 ![](https://img.kancloud.cn/ee/40/ee40025f5d8d79991845f1fd74e1f436_1569x486.png) * 找到spring-boot-starter-web 自动装配的程序包 ![](https://img.kancloud.cn/ed/2a/ed2acebad8ed92cc631e23111107ff20_1596x610.png) * 找到ServerProperties ![](https://img.kancloud.cn/d5/6c/d56c9271a255f10cd5da97527eab1706_1418x712.png) * 查找相关依赖 ![](https://img.kancloud.cn/a0/07/a00779586c9457610d751cdf3fb0f037_1062x470.png) * springboot 内置web容器中使用了ServerProperties,至于配置文件的server.port如何映射到ServerProperties,需要关注@ConfigurationProperties,springboot 内置容器将会以配置文件中的server.port启动 ![](https://img.kancloud.cn/68/7e/687e22b092e4e4461d7814e3f349ab1c_1000x869.png) * 启动back-center ![](https://img.kancloud.cn/7d/32/7d32f19b8d3285c1c12dcee4b374c8e4_1902x411.png) ## 静态资源 spring boot 启动如何知道前端的静态资料路径呢?你有没有遇到在springboot项目中放了一个html 报404呢? 下面分析源码。 * 涛声依旧,找到spring-boot-starter-web的源码包 ![](https://img.kancloud.cn/ed/2a/ed2acebad8ed92cc631e23111107ff20_1596x610.png) * 找到相关处理类 ![](https://img.kancloud.cn/a9/d8/a9d8c18070fe1cbc689ad7e261a71dc1_1529x574.png) * 回顾back-center代码,建立联系 ![](https://img.kancloud.cn/82/22/8222bede9c9478eec1e6dc3f2f9a76e4_1361x515.png) ## tomcat启动原理 ![](https://img.kancloud.cn/7a/d0/7ad0c2ef68eafb460538ccffd229b025_1774x546.png) ## tomcat 启动流程 ![](https://img.kancloud.cn/48/94/4894e83e6e7570a949ce2f180b431129_1657x870.png) ## 初始化连接器等信息 ![](https://img.kancloud.cn/53/5a/535a6219afd8fbbac5fb422fc15ce40c_1802x613.png) ## 内置tomcat处理能力配置情况查询 ![](https://img.kancloud.cn/9b/f5/9bf5e1e1ed36dfe51ee867df0eae1711_1755x762.png) ## 默认tomcat配置 ![](https://img.kancloud.cn/79/1e/791e299e672de6dcb698a22ae57175c0_917x275.png) ``` # 等待队列长度,默认100。队列也做缓冲池用,但也不能无限长,不但消耗内存,而且出队入队也消耗CPU server.tomcat.accept-count=1000 # 最大工作线程数,默认200。(4核8g内存,线程数800,一般是核数*200。操作系统做线程之间的切换调度是有系统开销的,所以不是越多越好。) server.tomcat.max-threads=800 # 最小工作空闲线程数,默认10。(适当增大一些,以便应对突然增长的访问量) server.tomcat.min-spare-threads=100 #最大连接数,默认为10000 server.tomcat.max-connections=10000 ``` **查看tomcat线程数命令如下:** 获取tomcat进程pid :ps -ef|grep tomcat 统计该tomcat进程内的线程个数 :ps -Lf 29295 |wc -l ## 优化理论 Tomcat在NIO模式时有一个线程专业接受请求连接,然后将其放到任务队列,然后有工作线程从任务t队列取出请求并并发处理(工作线程数通过maxThreads值控制,Tomcat默认是200),如果每个请求处理很快比如20ms,则工作线程1s内就能处理(1000/20*200)10000个请求,否则若请求处理很慢比如要几秒,则请求队列中的连接得到处理收到响应的时间也会变慢。 * maxThreads、minSpareThreads是tomcat工作线程池的配置参数,maxThreads就相当于jdk线程池的maxPoolSize,而minSpareThreads就相当于jdk线程池的corePoolSize。 * acceptCount、maxConnections是tcp层相关的参数。 ![](https://img.kancloud.cn/b2/94/b29415dcc69a1e994171e3073c0a7bc0_901x677.png) ## Tomcat与线程池 ![](https://img.kancloud.cn/49/20/4920c65138771724c48cdea0de7fce28_2264x689.png) ![](https://img.kancloud.cn/52/47/5247fb9efc8b4f3f99c000c95c00ebd5_2262x705.png) ## tomcat 执行流程 ![](https://img.kancloud.cn/e3/1d/e31d5238748258000368ed599edaa1d1_1300x269.png) 大致流程为: 1、创建一个Acceptor线程来接收用户连接,接收到之后扔到events queue队列里面,默认情况下只有一个线程来接收 2、创建Poller线程,数量小于等于2,Poller对象是NIO的核心,在Poller中,维护了一个Selector对象;当Poller从队列中取出socket后,注册到该Selector中;然后通过遍历Selector,找出其中可读的socket,然后扔到线程池中处理相应请求,这就是典型的NIO多路复用模型。 3、扔到线程池中的SocketProcessorBase处理请求 相较于BIO模型的tomcat,NIO的优势分析: 1、BIO中的流程应该是接收到请求之后直接把请求扔给线程池去做处理,在这个情况下一个连接即需要一个线程来处理,线程既需要读取数据还需要处理请求,线程占用时间长,很容易达到最大线程 2、NIO的流程的不同点在于Poller类采用了多路复用模型,即Poller类只有检查到可读或者可写的连接时才把当前连接扔给线程池来处理,这样的好处是大大节省了连接还不能读写时的处理时间(如读取请求数据),也就是说NIO“读取socket并交给Worker中的线程”这个过程是非阻塞的,当socket在等待下一个请求或等待释放时,并不会占用工作线程,因此Tomcat可以同时处理的socket数目远大于最大线程数,并发性能大大提高。 ## tomcat处理请求 ![](https://img.kancloud.cn/66/44/66448c24e93f0d7303a3303e8d1d945f_1552x1092.png) ## tomcat分发到DispatcherServlet ![](https://img.kancloud.cn/6d/99/6d995fc234f33a4a735d0ce5f3befcc8_1804x1025.png) ## web跳转API ``` redirectStrategy.sendRedirect(request, response, "http://www.baidu.com"); ``` ## request ,response ``` // 获得request对象,response对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); HttpServletResponse response = attributes.getResponse(); ``` ## ServletContext ``` ContextLoader.getCurrentWebApplicationContext().getServletContext() ``` 本章主要是说明spring-boot-starter-web启动的其中一部分,希望可以管中规豹,带你理解springboot的一些原理,spring-boot-starter到底做了什么,后面我们会陆续分析。 ## spring boot web开发 Spring Boot 全面支持开发 Restful 程序,通过不同的注解来支持前端的请求。 @GetMapping,处理 Get 请求 @PostMapping,处理 Post 请求 @PutMapping,用于更新资源 @DeleteMapping,处理删除请求 @PatchMapping,用于更新部分资源 这些组合注解是我们使用的@RequestMapping的简写版本,下面是 Java 类中的使用示例 @GetMapping(value="/xxx") 等价于 @RequestMapping(value = "/xxx",method = RequestMethod.GET) @PostMapping(value="/xxx") 等价于 @RequestMapping(value = "/xxx",method = RequestMethod.POST) @PutMapping(value="/xxx") 等价于 @RequestMapping(value = "/xxx",method = RequestMethod.PUT) @DeleteMapping(value="/xxx") 等价于 @RequestMapping(value = "/xxx",method = RequestMethod.DELETE) @PatchMapping(value="/xxx") 等价于 @RequestMapping(value = "/xxx",method = RequestMethod.PATCH)