Tomcat系统架构 浏览器访问服务器的流程 http请求的处理过程
Tomcat请求处理过程
Tomcat既按照Servlet的规范要求去实现了Servlet容器,同时也具有HTTP服务器的功能
Tomcat Servlet容器处理流程
1.HTTP服务器会将请求信息使用ServletRequest对象封装起来
2.根据URL映射调用Servlet容器中的某个具体的Servlet
3.若Servlet还未加载,则通过反射机制创建Servlet,并调用Servlet的init方法完成初始化
4.调用具体Servlet的service方法来处理请求,请求处理结果使用ServletResponse对象封装
5.将ServletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给客户端
Tomcat核心组件
根据上面的介绍,可以发现,Tomcat需要实现两个重要的功能
1.与客户端交互.进行请求响应对象转换
2.Servlet容器处理业务逻辑
下面介绍Tomcat的两个核心组件
连接器组件Coyote 负责对外交流,处理Socket连接,负责网络字节流与Request和Response对象的转化
容器Contalina 负责内部处理,加载和管理Servlet,以及具体处理Request请求
1.Engine
表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine,当一个引擎可以有多个Host
2.Host
代表一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机可以包含多个Context
3.Context
表示一个Web应用程序,一个Web应用可以包含多个Wrapper
4.Wrapper
表示一个Servlet,Wrapper作为容器中的最底层,不能包含子容器
上述组件的配置就体现在conf/server.xml中
Tomcat核心配置 配置说明 核心配置文件在tomcat目录下conf/server.xml
主要标签结构
<Server > <Listener /> <GlobalNamingResources /> <Service /> </Server >
Server标签
<Server port ="8005" shutdown ="SHUTDOWN" > <Listener className ="org.apache.catalina.startup.VersionLoggerListener" /> <Listener className ="org.apache.catalina.core.AprLifecycleListener" SSLEngine ="on" /> <Listener className ="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className ="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className ="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources > <Resource name ="UserDatabase" auth ="Container" type ="org.apache.catalina.UserDatabase" description ="User database that can be updated and saved" factory ="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname ="conf/tomcat-users.xml" /> </GlobalNamingResources > <Service name ="Catalina" > ... </Service > </Server >
Service标签
<Service name ="Catalina" > ... </Service >
Executor标签
<Executor name ="commonThreadPool" namePrefix ="thread-exec-" maxThreads ="200" minSpareThreads ="100" maxIdleTime ="60000" maxQueueSize ="Integer.MAX_VALUE" prestartminSpareThreads ="false" threadPriority ="5" className ="org.apache.catalina.core.StandardThreadExecutor" />
Connector标签
Connector 标签⽤于创建链接器实例
默认情况下,server.xml 配置了两个链接器,⼀个⽀持HTTP协议,⼀个⽀持AJP协议
⼤多数情况下,我们并不需要新增链接器配置,只是根据需要对已有链接器进⾏优化
<Connector port ="8080" protocol ="HTTP/1.1" connectionTimeout ="20000" redirectPort ="8443" /><Connector port ="8009" protocol ="AJP/1.3" redirectPort ="8443" />
Engine标签
<Engine name ="Catalina" defaultHost ="localhost" > ... </Engine >
Host标签
用于配置一个虚拟主机
<Host name ="localhost" appBase ="webapps" unpackWARs ="true" autoDeploy ="true" > ... </Host >
Context标签
Context标签用于配置一个Web应用
<Host name ="www.abc.com" appBase ="webapps" unpackWARs ="true" autoDeploy ="true" > <Context docBase ="/Users/yingdian/web_demo" path ="/web3" > </Context > <Valve className ="org.apache.catalina.valves.AccessLogValve" directory ="logs" prefix ="localhost_access_log" suffix =".txt" pattern ="%h %l %u %t " %r" %s %b" /> </Host >
手写简易版Tomcat 实现步骤
1.解析web.xml中的配置,保存url与servlet对象的映射关系
<?xml version="1.0" encoding="UTF-8" ?> <web-app > <servlet > <servlet-name > ww</servlet-name > <servlet-class > server.MyServlet</servlet-class > </servlet > <servlet-mapping > <servlet-name > ww</servlet-name > <url-pattern > /my</url-pattern > </servlet-mapping > </web-app >
private void loadServlet () { InputStream resourceAsStream = this .getClass().getClassLoader().getResourceAsStream("web.xml" ); SAXReader saxReader = new SAXReader (); try { Document document = saxReader.read(resourceAsStream); Element rootElement = document.getRootElement(); List<Element> selectNodes = rootElement.selectNodes("//servlet" ); for (int i = 0 ; i < selectNodes.size(); i++) { Element element = selectNodes.get(i); Element servletnameElement = (Element) element.selectSingleNode("servlet-name" ); String servletName = servletnameElement.getStringValue(); Element servletclassElement = (Element) element.selectSingleNode("servlet-class" ); String servletClass = servletclassElement.getStringValue(); Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']" ); String urlPattern = servletMapping.selectSingleNode("url-pattern" ).getStringValue(); servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance()); } } catch (DocumentException | IllegalAccessException | InstantiationException | ClassNotFoundException e) { e.printStackTrace(); } }
2.定义一个线程类,封装request,response对象,请求资源
private void loadServlet () { InputStream resourceAsStream = this .getClass().getClassLoader().getResourceAsStream("web.xml" ); SAXReader saxReader = new SAXReader (); try { Document document = saxReader.read(resourceAsStream); Element rootElement = document.getRootElement(); List<Element> selectNodes = rootElement.selectNodes("//servlet" ); for (int i = 0 ; i < selectNodes.size(); i++) { Element element = selectNodes.get(i); Element servletnameElement = (Element) element.selectSingleNode("servlet-name" ); String servletName = servletnameElement.getStringValue(); Element servletclassElement = (Element) element.selectSingleNode("servlet-class" ); String servletClass = servletclassElement.getStringValue(); Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']" ); String urlPattern = servletMapping.selectSingleNode("url-pattern" ).getStringValue(); servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance()); } } catch (DocumentException | IllegalAccessException | InstantiationException | ClassNotFoundException e) { e.printStackTrace(); } }
3.启动Socket监听,将线程类放入线程池
public void start () throws IOException { loadServlet(); int corePoolSize = 10 ; int maximumPoolSize = 50 ; long keepAliveTime = 100L ; TimeUnit unit = TimeUnit.SECONDS; ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue <>(50 ); ThreadFactory threadFactory = Executors.defaultThreadFactory(); RejectedExecutionHandler handler = new ThreadPoolExecutor .AbortPolicy(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor ( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler ); ServerSocket serverSocket = new ServerSocket (port); System.out.println("=====>>>Minicat start on port:" + port); System.out.println("=========>>>>>>使用线程池进行多线程改造" ); while (true ) { Socket socket = serverSocket.accept(); RequestProcessor requestProcessor = new RequestProcessor (socket,servletMap); threadPoolExecutor.execute(requestProcessor); }
4.请求localhost:8080/my之后,会进入HttpServlet的service进行处理,区分GET,POST请求
public void service (Request request, Response response) throws Exception { if ("GET" .equalsIgnoreCase(request.getMethod())) { doGet(request,response); }else { doPost(request,response); } }
源码剖析 Tomcat启动流程
Tomcat请求处理流程 流程分析
示意图
Mapper组件体系结构
Tomcat类加载机制 JVM类加载机制 类加载过程:Java类(.java)–>字节码文件(.class)–>字节码文件
引导启动类加载器
BootStrapClassLoader:加载java核心库文件,比如rt.jar中的类,构造ExtClassLoader和AppClassLoader
扩展类加载器
ExtClassLoader:加载扩展库JAVA_HOME/lib/ext目录下的jar中的类,如classpath中的jre,javax.*或者java.ext.dir指定位置中的类
系统类加载器
AppClassLoader/SystemCalssLoader:默认的类加载器,搜索环境变量classpath中指定的路径
双亲委派机制 当某个类加载器要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类.
作用
1.防止重复加载同一个.class
2.保证最上层的核心.class不能被篡改.
Tomcat类加载机制
1.系统类加载器正常情况下应该加载的是Classpath下的类,但是tomcat中加载的是tomcat的启动类,如bootstrap.jar
2.Common通用类加载器加载Tomcat使用以及应用通用的一些类,位于CATALINA_HOME/lib下,比如servlet-api.jar
3.Catalina ClassLoader用于加载服务器内部可见类
4.Shared ClassLoader用于加载应用程序共享类
5.Webapp ClassLoader,每个应用程序都有独一无二的Webapp ClassLoader,加载应用程序/WEB-INF/classes和/WEB-INF/lib下的类
加载顺序
1.首先从Bootstrap ClassLoader加载指定的类
2.如果未加载到,则从/WEB-INF/classes加载
3.如果未加载到,则从/WEB-INF/lib/*.jar加载
4.如果未加载到,则一次从Sytstem,Common,Shared加载
Tomcat优化策略 Tomcat支持HTTPS HTTP与HTTPS的区别 1.HTTPS需要使用SSL证书
2.Tomcat下HTTP默认端口8080,HTTPS默认端口8443
3.HTTPS具有安全性,会对数据传输加密,相当于HTTP的升级版
HTTPS工作原理
Tomcat配置HTTPS 1.使用JDK中的keytool工具生成免费的证书
keytool -genkey -alias lagou -keyalg RSA -keystore lagou.keystore
2.配置conf/server.xml
<Connector port ="8443" protocol ="org.apache.coyote.http11.Http11NioProtocol" maxThreads ="150" schema ="https" secure ="true" SSLEnabled ="true" > <SSLHostConfig > <Certificate certificateKeystoreFile ="a.keystore 证书文件地址" certificateKeystorePassword ="lagou123" type ="RSA" /> </SSLHostConfig > </Connector >
3.使用https协议访问localhost:8443
Tomcat性能优化 优化指标 1.响应时间:执行某个操作的耗时
2.吞吐量:系统在给定时间能支持的事务数量.单位TPS.
优化策略 1.虚拟机优化
内存直接影响服务的运行效率和吞吐量
垃圾回收机制会不同程度的导致程序运行中断
2.Tomcat配置优化
可以使⽤Nginx+Tomcat相结合的部署⽅案,Nginx负责静态资源访问,Tomcat负责Jsp等动态资源访问处理(因为Tomcat不擅⻓处理静态资源)