简易版Tomcat
Class Tomcat{
Connector connector;
List container;
}
整体上Tomcat由connector和container组成
第一步
从serlvet入口开始,servlet是一种规范
public class yunyunHttpServlet extends HttpServlet{
doGet(HttpServletRequest request, HttpServletResponse response)
}
其中HttpServletRequest和HttpServletResponse都是接口,这些接口需要实现类实现
当我们使用Tomcat时,则会使用Tomcat来实现这两个接口。
Tomcat会使用RequestFacade类和Request两个实现类实现这两个接口
Tomcat的两个Request类用了门面模式,开发者只能调用Request提供的方法,不能修改底层实现
第二步
那么yunyunHttpServlet 类下servlet这两个接口是如何知道调用Tomcat的Request类来实现呢
首先我们要知道war包和jar包的区别
本质上两者没有区别
规定Tomcat识别webapps下war包才能当成应用程序部署,否则必须在指定地方放入jar包才能识别
Tomcat部署有四种方式,其中可以通过war包达成Tomcat部署
然后Tomcat才知道从哪里读取文件
在war包下会有很多class文件和xml(class文件和名称映射)
比如有
<servlet>
<servlet-name>yunyunHttpServlet</servlet-name>
<servlet-class>com.woaiyunyun.yunyunHttpServlet</~>
</servlet>
<servlet-mapping>
<servlet-name>yunyunHttpServlet</~>
<url-pattern>/yunyunHttp</~>
</~>
因为配置过了映射关系,当我们调用yunyunHttpServlet下doGet方法,则会调用Tomcat具体实现类
第三步
那么Tomcat的request的实现类底层又是如何实现的呢
Connector:
当数据从操作系统传入进来时候,我们上文所说Tomcat两大快Connector下Endpoint
会根据名字如Http1.1,AJP/1.3等等来决定用哪个NIO/BIO等等来读取数据
其中在通过socket获取data用到了线程池,线程池大小也是我们后面可以调优的参数
在Connector下解析中就是对Tomcat request接口实现类的不断赋值,然后传递给你Container容器
Container:
在容器下以责任链模式,每层都是一个可以自定义实现的管道。每层管道都可以进行一层处理到下一个管道,比如每个管道记录日志
Engine – 主机管理引擎
Host – 主机
Context – 应用
Wrapper – 封装多个Servlet
Servlet – 应用下一个程序
其中Tomcat本身只会调用service方法,当Http请求是get则只需doGet方法,doPost
是Servlet规范写好的
简单例子责任链模式
class HTMLFilter implements Filter{
@Override
Public boolean service(Request request, Response response, FilterChain chain){
1. 处理request(doGet)
2. 递归chain.doFilter
3. 处理response(doPost)
}
}
责任链模式先稍微提及,在后面讲23种设计模式章节具体讲
就此tomcat执行完毕
1 为什么要用SpringMVC
2 Tomcat有安全管理器
A有权限,B无权限时候
AccessController.doPrivileged方法给B调用A中权限方法
\bin > startup.bat -security 安全管理机制运行tomcat
3 热加载和热部署的区别
热部署是Tomcat默认打开,热加载需要手动打开
热部署在服务器运行时重新部署项目。
热加载在运行时重新加载class。
热加载监控web-inf下class等变化
Web-inf下lib下jar包有无增加删除(比如通过class文件修改时间比较来判断)
4 Tomcat类加载器
为什么Tomcat下每个应用都会先走自己的类加载器?
因为不同应用可能有相同的名字的类,但是功能却不同
Context下类加载器
第一步:在缓存map中找想加载的class的路径path(key: xxx.className, value: class对线的路径)
第二步: 如果map没有,看JVM是否加载过(JVM本地方法)
第三步:查看是否开启委托父类中找设置,如果开启直接父类加载器中找
如果未开启就自己路径下找并map缓存,如果仍没找到则走父类加载器
5 Tomcat如何实现异步servlet
走到Wrapper管道时,调用service后会封装一个AsyncContext对象,该对线封装了request和response方法,之后线程池就回收此线程了,用client自己线程池来真正处理这个这个context对象,完成业务逻辑后再通知tomcat已处理完成,然后tomcat对该对象再回收或关闭连接
1
配置项-----------------------------------默认-----------------建议
Connection Timeout-----------------20s------------------减少
(连接超时时间)
maxThreds-----------------------------200-----------------增加(不是越大越好)
(处理连接最大线程数,吞吐量)
acceptCount(backlog) --------------100 ----------------增加
(操作系统中接受请求的数量限制)
MaxConnections----------------------nio 1万------------不变
(Tomcat中接受请求数量限制,当Tomcat限制满了则会放入OS下acceptCount中)
2
线程线程数量
Windows下 maxThread = acceptCount + MaxConnections
Linux下 maxThread = TCPQueue(不可控一般不管) + acceptCount + MaxConnections
3
Linux下配置参数,不断调试启动项目,看运行情况 java -jar demo.jar -server tomcat.maxConnection=xxx …
Linux下ps看CPU利用率等
可用Jmeter程序调优,启动该程序,输入IP Port即可测试
Jmeter下看Http请求状态,吞吐量等
4
调maxConnections情况
当maxThread > maxConnections时, maxConnections应稍大于MaxThreads
调acceptCount情况
一般不改,在OS层面不可控因素大
Tomcat默认100, linux默认128
调maxThreads情况(调优核心)
理想线程数量= (1+code block time/code execute time)*cpu数量
实际是跑代码,压测下调试,不断调线程数将CPU利用率控制在百分之80-90之间,当CPU利用率超过百分之90则增加maxThreads