🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 一、启动关闭tomcat 需要先配置CATALINA_HOME 双击%CATALINA_HOME%\bin\startup.bat 双击%CATALINA_HOME%\bin\shutdown.bat  访问服务器:http://localhost:8080/index.jsp 因为服务器在本机上,所以主机名为localhost,表示本机 tomcat的默认端口为8080 index.jsp是主页 # 二、修改端口号 修改端口号,%CATALINA_HOME%\conf\server.xml,修改,把8080修改了即可。 http协议默认端口为80,也就是说http://localhost,等同与http://localhost:80 如果把Tomcat端口号修改成80,那么访问服务器就可以无需再给出端口号。 # 三.tomcat目录结构 ![](http://h.yiniuedu.com/42813e3ba1fff6abb3c6bd945736427e) 1.bin:二进制可执行文件,例如startup.bat和shutdown.bat >[danger]/bin目录 存放windows或者是Linux启动和关闭tomcat的脚本文件 /bin/catalina.sh 用于启动和关闭tomcat服务器 /bin/configtest.sh 用于检查配置文件 /bin/startup.sh 启动Tomcat脚本 /bin/shutdown.sh 关闭Tomcat脚本 2.conf:配置文件,例如:server.xml、context.xml、web.xml、tomcat-users.xml >[danger]/conf目录 存放tomcat服务器的各种全局配置文件其中包括server.xml(Tomcat的主要配置文件)、tomcat-users.xml和web.xml等配置文件 /conf/server.xml Tomcat 的全局配置文件 /conf/web.xml 为不同的Tomcat配置的web应用设置缺省值的文件 /conf/tomcat-users.xml Tomcat用户认证的配置文件 3.lib:tomcat所需jar包 >[danger]/lib目录 存放Tomcat服务器运行所需的各种JAR文件(不能被web应用访问) 4.logs:日志文件 >[danger]/logs目录 存放Tomcat执行时的Log日志文件 /logs/localhost_access_log.*.txt 访问日志 /logs/localhost.*.log 错误和其它日志 /logs/manager.*.log 管理日志 /logs/catalina.*.log Tomcat启动或关闭日志文件 5.temp:存放tomcat运行时产生的临时文件,当tomcat关闭后,这个目录中的文件可以删除 >[danger]/temp目录 存放Tomcat运行时所产临时文件 6.webapps:这个目录下的每个文件夹对应一个JavaWeb应用程序 >[danger]/webapps目录 Tomcat的主要Web发布目录,默认情况下把Web应用文件放于此目录(存放我们自己的JSP,Servlet类) 7.work:webapps下的应用程序在运行时会自动生成文件,就在work目录下。work目录删除了也没问题,但再次运行应用程序还要再生成work目录和文件。 >[danger]/work目录 Tomcat的工作目录,将JSP生成的Servlet源文件和字节码文件放到这个目录下 work目录下的文件 由Tomcat自动生成,这是Tomcat放置它运行期间的中间(intermediate)文件(诸如编译的JSP文件)地方。 如果当Tomcat运行时,你删除了这个目录那么将不能够执行包含JSP的页面。 # 四.创建JavaWeb目录:hello 1. 在webapps目录下创建一个hello目录,hello目录就是项目目录了; 2. 在hello目录下创建WEB-INF 3. 在WEB-INF下创建web.xml 4. 在WEB-INF下创建classes目录 5. 在WEB-INF下创建lib目录 6. 在hello目录下创建index.html   在web.xml文件中添加如下内容: ``` <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> </web-app> ```   在index.html中添加如下内容: ``` <html> <head> <!--如果是html页面,charset设置为gb2312,可以防止出现乱码--> <meta charset="gb2312"/> <title>index.html</title></head> <body> <h1>hello主页</h1> </body> </html> ```   启动tomcat,打开客户端访问http://localhost:8080/hello/index.html 配置外部应用   外部应用既是把应用程序不放到Tomcat的wabapps目录下!而已放在外面,例如:d:/hello 在conf/server.xml下配置,指定外部应用的路径。 ``` <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="yiniuedu_hello" docBase="d:/hello"/> </Host> ``` 在元素下添加元素,path为URL访问路径,docBase为外部应用的目录。 在浏览器地址栏中访问:http://localhost:8080/yiniuedu_hello/index.html 在conf/catalna/localhost下添加配置文件,指定外部应用路径 在conf/catalna/localhost目录下创建yiniuedu_hello.xml文件,其中yiniuedu_hello就是URL访问路径 在yiniuedu_hello.xml文件中添加:,docBase指定外部应用的目录。 缺省web应用 在webapps目录下有一个ROOT目录,它是缺省web应用,访问这个应用的路径:http://localhost:8080/index.jsp 如果把web应用的内部放到webapps/ROOT下,访问URL路径中不用给出应用名称。 配置虚拟主机 希望:http://cms.yiniuedu.com访问web应用。 这需要把域名http://cms.yiniuedu.com映射成IP地址:127.0.0.1 需要把tomcat端口号修改为80 需要在server.xml中配置主机,并指定主机的应用目录 在应用目录中添加名为ROOT的web应用。 1). 找到C:\WINDOWS\system32\drivers\etc\hosts文件,添加127.0.0.1 http://cms.yiniuedu.com 2). 在conf/server.xml中修改端口为80 3). 在conf/server.xml中添加元素 ``` <Host name="cms.yiniuedu.com" appBase="d:/myapps" unpackWARs="true" autoDeploy="true"> </Host> ``` * name:指定该主机域名为cms.yiniuedu.com * appBase:指定该主机的应用目录为d:/myapps 4). 在d:/myapps下创建名为ROOT的web应用。 # 五、tomcat服务器顶层结构 免费、开源、跨平台的Tomcat无疑是我们开始学习Java EE的第一个服务器,会用对于日常开发完全够用了,但是还是要学一下Tomcat相关的原理和设计思想等,对于以后相关的扩展和优化有着重要的作用。下边是学习Tomcat,翻看Tomcat源码的一些总结和感悟,作为笔记查看。 ## 1、Tomcat服务器顶层结构 俗话说,站在巨人的肩膀上看世界,一般学习的时候也是先总览一下整体,然后逐个部分个个击破,最后形成思路,了解具体细节。Tomcat 的结构很复杂,但是 Tomcat 也非常的模块化,找到了 Tomcat 最核心的模块,问题才可以游刃而解。先上一张Tomcat的顶层结构图,如下: ![](http://h.yiniuedu.com/4937477b6b0bacdcb78e2aad497f57f9) Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务。 Service主要包含两个部分:Connector和Container。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下: Connector用于处理链接相关的事情,并提供Socket与Request和Response相关的转化; Container用于封装和管理Servlet,以及具体处理Request请求; 一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供http和https链接,也可以提供向相同协议不同端口的连接。 多个 Connector 和一个 Container 就形成了一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非 Server 莫属了。所以整个 Tomcat 的生命周期由 Server 控制。 另外,上述的包含关系或者说是父子关系,都可以在tomcat的conf目录下的server.xml配置文件中看出,下图是删除了注释内容之后的一个完整的server.xml配置文件(Tomcat版本为8.0) ![](http://h.yiniuedu.com/1658e4f55f8d8d932c9436d6025f0d83) 详细的配置文件文件内容可以到Tomcat官网查看:[http://tomcat.apache.org/tomcat-8.0-doc/index.html](http://tomcat.apache.org/tomcat-8.0-doc/index.html) 上边的配置文件,还可以通过下边的一张结构图更清楚的理解: ![](http://h.yiniuedu.com/2fa9acc36b516832eaf2fb5b6969d528) Server标签设置的端口号为8005,shutdown=”SHUTDOWN” ,表示在8005端口监听“SHUTDOWN”命令,如果接收到了就会关闭Tomcat。一个Server有一个Service,当然还可以进行配置,一个Service有多个,Service左边的内容都属于Container的,Service下边是Connector。 总结: Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container。 ## 2、Tomcat的启动过程 首先看一张Tomcat启动的时序图,如下: ![](http://h.yiniuedu.com/87d46e678458439bb25720785994aeea) Tomcat的启动入口main方法是在Bootstrap类里,但具体的执行过程是在Catalina里边,这样做可以使得把启动的入口和具体的管理类进行分开,从而可以方便的创建多种启动的方式。 Catalina是整个Tomcat的管理类,他有三个方法load、start、stop分别用来管理整个服务器的生命周期。load方法用于加载tomcat/conf目录下的server.xml配置文件,用来创建Server并调用Server的init方法进行初始化操作,start用于启动服务器器,stop用于停止服务器,start和stop方法在内部分别调用Server的start和stop方法,load方法在内部调用了 Server的init方法,这三个方法都会按层次分逐层调用相应的方法。 从上述的时序图,按着从上到下,从左到右的顺序,完全可以了解整个Tomcat的启动顺序。 上图中看到了几个陌生的名字,下边具体说明。 ### 2.1、Bootstrap的启动过程 Bootstrap作为Tomcat的启动入口,其main方法如下: ``` public static void main(String args[]) { //首先判断Bootstrap daemon 是否为空,就是创建一个Bootstrap实例daemon if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); //初始化ClassLoader,并用ClassLoader创建了一个Catalina实例,并将这个实例赋值给了cataLinaDaemon } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent // a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String command = "start"; //指定默认的执行指令是start if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); //BootStrap的load方法,其实是调用Calatina的load方法 daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); //setWait方法 主要是为了设置Server启动完成后是否进入等待状态的标志,如果为true则进入,否则不进入 daemon.load(args); //load方法用于加载配置文件,创建并初始化Server daemon.start(); //start方法用于启动服务器 } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } } ``` (1)上述执行的bootstrap.init()方法源代码如下: ![](http://h.yiniuedu.com/18c295a4602c6234f7a8e818cda9f579) (2)main方法里边,首先创建一个Bootstrap,并执行init方法进行初始化,然后出来main方法里传入的参数,如果参数为空,默认为start。 (3)在init方法里初始化ClassLoader,并用ClassLoader创建了Catalina实例,然后赋值给catalinaDaemon变量,后边对命令的操作都要使用catalinaDaemon来具体的执行; (4)在start命令的处理调用的时候有三个方法:setAwait、load 、start。这三个方法在内部调用了Clatalina的相应的方法进行具体的执行,只不过是用反射来调用的。 ### 2.2、Catalina的启动过程 Catalina的启动主要调用setAwait、load和start方法来实现,setAwait方法用于设置Server启动完成后是否进入等待状态的标志,如果为true则进入,否则不进入;load方法用于加载配置文件,创建并初始化Server;start用于启动服务器。 Catalina的load方法根据con/server.xml文件进行创建对象的,并赋值给server属性。 ### 2.3、Server的启动过程 Server是一个接口,继承自Lifecycle ,接口定义如下: ``` public interface Server extends Lifecycle { } ``` ![](http://h.yiniuedu.com/ca3f923f9e748aac48d56205f00c93c3) 看接口的结构图可以看出,其中包含了addService、findService、removeService三个主要的方法,用来增加、查找、删除Service。Server的init方法和start方法分别循环调用了每个Service方init方法和start方法来启动所有的Service。 Server 的默认实现是:org.apache.catalina.core.StandardServer,继承关系图如下: ![](http://h.yiniuedu.com/e26bd4835736986bb70bb56f79534c20) StandardServer的initInternal和startInternal方法分别循环调用了每一个Service的start和init方法。 ![](http://h.yiniuedu.com/22aa146975e882f530953868db664baf) ### 2.4、Service的启动过程 Service是一个接口,继承自Lifecycle ,接口定义如下: ~~~ public interface Service extends Lifecycle { } ~~~ Service 接口定义的方法和属性如下: ![](http://h.yiniuedu.com/da2187fb3714f59686c0c4388f5a354e) Service的默认实现是:org.apache.catalina.core.StandardService。StandardService和StandardServer有相似的继承关系,如下图: ![](http://h.yiniuedu.com/f1c01efcda4b95dbd7e9205088277e90) StandardService的initInternal方法如下: ``` @Override protected void initInternal() throws LifecycleException { super.initInternal(); if (engine != null) { engine.init(); } // Initialize any Executors for (Executor executor : findExecutors()) { if (executor instanceof JmxEnabled) { ((JmxEnabled) executor).setDomain(getDomain()); } executor.init(); } // Initialize mapper listener mapperListener.init(); // Initialize our defined Connectors synchronized (connectorsLock) { for (Connector connector : connectors) { connector.init(); } } } ``` StandardService的startInternal方法如下 ``` @Override protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); setState(LifecycleState.STARTING); // Start our defined Container first if (engine != null) { synchronized (engine) { engine.start(); } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } mapperListener.start(); // Start our defined Connectors second synchronized (connectorsLock) { for (Connector connector: connectors) { // If it has already failed, don't try and start it if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } } } ``` 可以看出,StandardService的initInternal和startInternal方法主要调用container、executors、mapperListener、connectors的init和start方法。 mapperListener是Mapper的监听器,用来监听Container容器的变化;executors是用在connectors中管理线程的线程池,在server.xml文件中可以看到,默认是注释的: ![](http://h.yiniuedu.com/350e8b5cf889ca26c28c333345cc262c) ## 3、总结 上述的几小节,大致记录了一下Tomcat的整体结构,在上边介绍的时候,也有一些没有写到的东西,比如说Tomcat生命周期管理的接口Lifecycle、Connector、Container以及Tomcat如何进行通信,如何解析和处理具体的Http请求,这些会在以后的学习中不断记录下来。