设为首页 收藏本站
查看: 634|回复: 0

[经验分享] tomcat 源码学习

[复制链接]

尚未签到

发表于 2017-1-18 10:04:20 | 显示全部楼层 |阅读模式
  Tomcat从5.5版本开始,支持以下四种Connector的配置分别为 NIO, HTTP, POOL, NIOP:
  <Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443"/>
  <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
  <Connector executor="tomcatThreadPool"port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
  <Connector executor="tomcatThreadPool" port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />
  NetworkClient
  -->Socket-->PlainSocketImpl的native void socketConnect(InetAddress paramInetAddress, int paramInt1, int paramInt2)
  NetworkServer
  带main方法的ServerSocket
  HttpURLConnection
  -->HttpClient extends NetworkClient
  tomcat 如何通过jmx loader 、digester架构
  一、目录结构:
  apache-tomcat-5.5.23\server\lib
  apache-tomcat-5.5.23\common\lib
  conf\context.xml
  <Context><WatchedResource>WEB-INF/web.xml</WatchedResource></Context>
  conf\web.xml
  这个里面的加载                
  jasper-compiler.jar负责把index_jsp转化成index_jsp.servlet,(当首次访问该jsp时)
  apache-tomcat-5.5.23\work\Catalina\localhost\myservlet\org\apache\jsp\index_jsp
  二、
  conf\server.xml元素结构
  <Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
  <Service name="Catalina">
  //1、端口。将port=80,进入本地服务时就不用敲80在末尾了(浏览器默认),这样当安装了IIS服务(80端口)时,tomcat无法启动(它是serversocket)。
  <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443" useBodyEncodingForURI="true"/>
  <Engine defaultHost="localhost" name="Catalina">
  <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
  <Context docBase="mypushlet" path="/mypushlet" reloadable="true" source="org.eclipse.jst.jee.server:mypushlet"/>
  </Host>
  </Engine>
  </Service>
  </Server>
  2.虚拟目录:所有的开发程序【JSP、servlet文件】保存在虚拟目录中。
  设虚拟目录 "myweb",通过 http://localhost:8080/myweb 访问物理路径 L:\java\JWeb 文件夹里面的内容。设置过程如下: 
  1.复制 Tomcat6.0\webapps\ROOT 目录下的 WEB-INF 文件夹到 L:\java\JWeb 目录下。 
  2.打开L:\java\JWeb\WEB-INF 目录下的 web.xml 文件,在 </description> 之后加入: 
  <!--JSPC servlet mappings start --> 
  <!--JSPC servlet mappings end --> 
  3.打开 Tomcat6.0\conf\server.xml 文件,在 <Host> 和 </Host> 之间加入: 
  <Context path="/myweb" docBase="L:\java\JWeb"></Context> 
  path="/myweb" 就是虚拟目录的名称 
  docBase="L:\java\JWeb"> 为物理路径 
  4.打开 Tomcat6.0\conf\web.xml 文件,找到: 
  <init-param> 
  <param-name>listings</param-name> 
  <param-value>false</param-value> 
  </init-param> 
  把false设成true保存,重启Tomcat,现在就可以应用 http://localhost:8080/myweb 虚拟目录了。 
  1.1 - Server 
  A Server element represents the entire Catalina servlet container. (Singleton) 
  1.2 - Service 
  A Service element represents the combination of one or more Connector components that share a single Engine 
  Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求 
  1.3 - Connector 
  一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户。 
  Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求 
  Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求 
  1.4 - Engine 
  An Engine is a Container that represents the entire Catalina servlet engine. 
  If used, an Engine is always the top level Container in a Catalina.
  Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名。 
  当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理
  1.5 - Host 
  架构:
  Server: 其实就是BackGroud程序, 在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令。SHUTDOWN)
  Service: 一类问题的解决方案。默认使用Tomcat-Standalone 模式的service。既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务。
  Connector:从socket传递过来的数据, 封装成Request, 传递给容器来处理。http、https、ajp(apache与tomcat)三种
  Container: 当http connector把需求传递给顶级的container: Engin的时候, 我们的视线就应该移动到Container这个层面来了。
  在Container这个层, 我们包含了3种容器: Engin, Host, Context.
  Engin: 收到service传递过来的需求, 处理后, 将结果返回给service( service 是通过 connector 这个媒介来和Engin互动的 ).
  Host: Engin收到service传递过来的需求后,不会自己处理, 而是交给合适的Host来处理。
  Host在这里就是虚拟主机的意思, 通常我们都只会使用一个主机,既“localhost”本地机来处理。 
  Context: 一个web app,Host接到了从Host传过来的需求后, 也不会自己处理, 而是交给合适的Context来处理。 
  Compenent: 容器有各种各样的组件, 提供各种各样的增值服务。
  manager: 当一个容器里面装了manager组件后,这个容器就支持session管理了, 事实上在tomcat里面的session管理, 就是靠的在context里面装的manager component.
  logger: 当一个容器里面装了logger组件后
  loader: 通常只会给我们的context容器使用, loader是用来启动context以及管理这个context的classloader用的。
  pipline: 容器间传递并过滤。
  2. Tomcat的启动流程: 第一步是装配工作(父容器装上子容器,容器安插进组件)。 第二步是启动工作。 
  2.3 Catalina.java
  1. 使用Digester技术装配tomcat各个容器与组件。
  1.1 装配工作的主要内容是安装各个大件。 比如server下有什么样的servcie。 Host会容纳多少个context。 Context都会使用到哪些组件等等。 
  1.2 同时呢, 在装配工作这一步, 还完成了mbeans的配置工作。 在这里,我简单地但不十分精确地描述一下mbean是什么,干什么用的。
  我们自己生成的对象, 自己管理, 天经地义! 但是如果我们创建了对象了, 想让别人来管, 怎么办呢? 我想至少得告诉别人我们都有什么, 以及通过什么方法可以找到 吧! JMX技术给我们提供了一种手段。 JMX里面主要有3种东西。Mbean, agent, connector.
  Mbean: 用来映射我们的对象。也许mbean就是我们创建的对象, 也许不是, 但有了它, 就可以引用到我们的对象了。
  Agent: 通过它, 就可以找到mbean了。
  Connector: 连接Agent的方式。 可以是http的, 也可以是rmi的,还可以直接通过socket。
  发生在tomcat 装配过程中的事情: GlobalResourcesLifecycleListener 类的初始化会被触发:
  protected static Registry registry = MBeanUtils.createRegistry(); 会运行
  MBeanUtils.createRegistry() 会依据/org/apache/catalina/mbeans/mbeans-descriptors.xml这个配置文件创建 mbeans. Ok, 外界就有了条途径访问tomcat中的各个组件了。
  2. 为top level 的server 做初始化工作。 实际上就是做通常会配置给service的两条connector.(http, ajp)
  3. 从server这个容器开始启动, 点燃整个tomcat.
  4. 为server做一个hook程序, 检测当server shutdown的时候, 关闭tomcat的各个容器用。
  5. 监听8005端口, 如果发送"SHUTDOWN"(默认培植下字符串)过来, 关闭8005serverSocket。
  2.4 启动各个容器
  1. Server
  触发Server容器启动前(before_start), 启动中(start), 启动后(after_start)3个事件, 并运行相应的事件处理器。
  启动Server的子容器:Servcie. 
  2. Service
  启动Service的子容器:Engin
  启动Connector
  3. Engin
  到了Engin这个层次,以及以下级别的容器, Tomcat就使用了比较一致的启动方式了。
  首先, 运行各个容器自己特有一些任务
  随后, 触发启动前事件
  立即, 设置标签,就表示该容器已经启动
  接着, 启动容器中的各个组件: loader, logger, manager等等
  再接着,启动mapping组件。(注1)
  紧跟着,启动子容器。
  接下来,启动该容器的管道(pipline)
  然后, 触发启动中事件
  最后, 触发启动后事件。
  Engin大致会这么做, Host大致也会这么做, Context大致还是会这么做。 那么很显然地, 我们需要在这里使用到代码复用的技术。 tomcat在处理这个问题的时候, 漂亮地使用了抽象类来处理。 ContainerBase. 最后使得这部分完成复杂功能的代码显得干净利落, 干练爽快, 实在是令人觉得叹为观止, 细细品来, 直觉如享佳珍, 另人齿颊留香, 留恋往返啊!
  Engin的触发启动前事件里, 会激活绑定在Engin上的唯一一个Listener:EnginConfig。
  这个EnginConfig类基本上没有做什么事情, 就是把EnginConfig的调试级别设置为和Engin相当。 另外就是输出几行文本, 表示Engin已经配置完毕, 并没有做什么实质性的工作。
  注1: mapping组件的用处是, 当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢? 这个由mapping 组件来定夺。
  4. Host
  同Engin一样, 也是调用ContainerBase里面的start()方法, 不过之前做了些自个儿的任务,就是往Host这个容器的通道(pipline)里面, 安装了一个叫做
  “org.apache.catalina.valves.ErrorReportValve”的阀门。
  这个阀门的用处是这样的: 需求在被Engin传递给Host后, 会继续传递给Context做具体的处理。 这里需求其实就是作为参数传递的Request, Response。 所以在context把需求处理完后, 通常会改动response。 而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误, 如果有就做相应的处理。
  5. Context
  到了这里, 就终于轮到了tomcat启动中真正的重头戏,启动Context了。
  StandardContext.start() 这个启动Context容器的方法被StandardHost调用.
  5.1 webappResources 该context所指向的具体目录
  5.2 安装defaultContex, DefaultContext 就是默认Context。 如果我们在一个Host下面安装了DefaultContext,而且defaultContext里面又安装了一个数据库连接池资源的话。 那么其他所有的在该Host下的Context, 都可以直接使用这个数据库连接池, 而不用格外做配置了。
  5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoader这个类。   Loader就是用来指定这个context会用到哪些类啊, 哪些jar包啊这些什么的。
  5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager 。 Manager是用来管理session的。
  其实session的管理也很好实现。 以一种简单的session管理为例。 当需求传递过来的时候, 在Request对象里面有一个sessionId 属性。 OK, 得到这个sessionId后, 我们就可以把它作为map的key,而value我们可以放置一个HashMap. HashMap里边儿, 再放我们想放的东西。
  5.5 postWorkDirectory (). Tomcat下面有一个work目录。 我们把临时文件都扔在那儿去。 这个步骤就是在那里创建一个目录。 一般说来会在%CATALINA_HOME%/work/Standalone\localhost\ 这个地方生成一个目录。
  5.6 Binding thread。到了这里, 就应该发生 class Loader 互换了。 之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class。 所以要设置contextClassLoader, 同时还要把旧的ClassLoader记录下来,因为以后还要用的。
  5.7 启动 Loader. 指定这个Context具体要使用哪些classes, 用到哪些jar文件。 如果reloadable设置成了true, 就会启动一个线程来监视classes的变化, 如果有变化就重新启动Context。
  5.8 启动logger
  5.9 触发安装在它身上的一个监听器。
  lifecycle.fireLifecycleEvent(START_EVENT, null); 
  作为监听器之一,ContextConfig会被启动. ContextConfig就是用来配置web.xml的。 比如这个Context有多少Servlet, 又有多少Filter, 就是在这里给Context装上去的。
  5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml 这个文件。
  5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文件
  5.9.3 validateSecurityRoles 权限验证。 通常我们在访问/admin 或者/manager的时候,需要用户要么是admin的要么是manager的, 才能访问。 而且我们还可以限制那些资源可以访问, 而哪些不能。 都是在这里实现的。
  5.9.4 tldScan: 扫描一下, 需要用到哪些标签(tag lab)
  5.10 启动 manager
  5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称:
  index.html、index.htm、index.jsp 就被默认地绑在了这个context上
  5.12 listenerStart 配置listener
  5.13 filterStart 配置 filter
  5.14 启动带有<load-on-startup>1</load-on-startup>的Servlet.
  顺序是从小到大: 1,2,3… 最后是0
  默认情况下, 至少会启动如下3个的Servlet: 
  org.apache.catalina.servlets.DefaultServlet   
  处理静态资源的Servlet. 什么图片啊, html啊, css啊, js啊都找他
  org.apache.catalina.servlets.InvokerServlet
  处理没有做Servlet Mapping的那些Servlet.
  org.apache.jasper.servlet.JspServlet 
  处理JSP文件的.
  5.15 标识context已经启动完毕,tomcat启动完毕。
  /**
  * A <b>Host</b> is a Container that represents a virtual host in the
  * Catalina servlet engine.  It is useful in the following types of scenarios:
  * <ul>
  * <li>You wish to use Interceptors that see every single request processed
  *     by this particular virtual host.
  * <li>You wish to run Catalina in with a standalone HTTP connector, but still
  *     want support for multiple virtual hosts.
  * </ul>
  * In general, you would not use a Host when deploying Catalina connected
  * to a web server (such as Apache), because the Connector will have
  * utilized the web server's facilities to determine which Context (or
  * perhaps even which Wrapper) should be utilized to process this request.
  * <p>
  * The parent Container attached to a Host is generally an Engine, but may
  * be some other implementation, or may be omitted if it is not necessary.
  * <p>
  * The child containers attached to a Host are generally implementations
  * of Context (representing an individual servlet context).
  */        
  每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path。 
  当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。
  1.6 - Context 
  一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成。
  Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。
  当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。 
  1.7 - 示例
  browser发送请求到本机端口8080--> Connector --> Engine --> Host --> Context --> servlet 构造request、response --> Context --> Host --> Engine -- > connector --> browser
  public final class Bootstrap{
  private static Bootstrap daemon = null;
  private Object catalinaDaemon;
  protected ClassLoader commonLoader;
  protected ClassLoader catalinaLoader;
  protected ClassLoader sharedLoader;//Webapp1Loader  Webapp2Loader ... 
  public Bootstrap(){...}
  private void initClassLoaders(){...}
  catalinaDaemon = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina").newInstance();
  public void start()throws Exception{
  Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null);
  method.invoke(this.catalinaDaemon, (Object[])null);
  }
  }
  public class StandardService implements Lifecycle, Service, MBeanRegistration 
  protected Connector connectors[] = new Connector[0];
  protected ArrayList<Executor> executors = new ArrayList<Executor>();
  /** 
  * this holds the most recently added Engine.is generally an instance of Engine
  */
  protected Container container = null;
  /**
  * The lifecycle event support for this component.
  */
  private LifecycleSupport lifecycle = new LifecycleSupport(this);
  /**
  * The <code>Server</code> that owns this Service, if any.
  */
  private Server server = null;
  /**
  * The property change support for this component.
  */
  protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  public void addConnector(Connector connector) {}
  public void addPropertyChangeListener(PropertyChangeListener listener) {}
  public void addExecutor(Executor ex) {}
  public void addLifecycleListener(LifecycleListener listener) {}
  }
  //embed [im'bed] 嵌入
  public class Embedded  extends StandardServic{
  public synchronized void addEngine(Engine engine) {}
  }
  //启动Tomcat,就生成Catalina实例,server实例????
  根据配置文件server.xml,实例化的对象。对象实例化过程中,会做载入webapp,在特定端口等待客户连接等工作。 
  从server.xml到对象的映射是通过commons-digester.jar包完成的。这个包的一个主要功能就是映射xml到java对象。
  public class Catalina extends Embedded {
  protected String configFile = "conf/server.xml";
  /**
  * The application main program.
  * @param args Command line arguments
  */
  public static void main(String args[]) {
  (new Catalina()).process(args);
  }
  /**
  * The instance main program.
  * @param args Command line arguments
  */
  public void process(String args[]) {
  load(args);
  start();
  }
  /**
  * Start a new server instance.
  */
  public void start() {
  ((Lifecycle) getServer()).start();
  }
  protected Digester createStartDigester() {
  digester.addObjectCreate("Server",
  "org.apache.catalina.core.StandardServer",
  "className");
  digester.addSetProperties("Server");
  digester.addSetNext("Server",
  "setServer",
  "org.apache.catalina.Server");
  digester.addSetNext("Server/GlobalNamingResources",
  "setGlobalNamingResources",
  "org.apache.catalina.deploy.NamingResources");
  digester.addSetNext("Server/Listener",
  "addLifecycleListener",
  "org.apache.catalina.LifecycleListener");
  digester.addSetNext("Server/Service",
  "addService",
  "org.apache.catalina.Service");
  digester.addSetNext("Server/Service/Listener",
  "addLifecycleListener",
  "org.apache.catalina.LifecycleListener");
  digester.addSetNext("Server/Service/Executor",
  "addExecutor",
  "org.apache.catalina.Executor");
  digester.addSetNext("Server/Service/Connector",
  "addConnector",
  "org.apache.catalina.connector.Connector");
  digester.addSetNext("Server/Service/Connector/Listener",
  "addLifecycleListener",
  "org.apache.catalina.LifecycleListener");
  }
  }
  //available for use(but not required) when deploying and starting Catalina.        
  public final class StandardServer implements Lifecycle, Server, MBeanRegistration{ 
  public StandardServer() {
  ServerFactory.setServer(this);
  globalNamingResources = new NamingResources();
  globalNamingResources.setContainer(this);
  if (isUseNaming()) {
  if (namingContextListener == null) {
  namingContextListener = new NamingContextListener();
  addLifecycleListener(namingContextListener);
  }
  }
  }
  private javax.naming.Context globalNamingContext = null;
  private NamingResources globalNamingResources = null;
  private NamingContextListener namingContextListener = null;
  /**
  * The port number on which we wait for shutdown commands.
  */
  private int port = 8005;
  awaitSocket = new ServerSocket(port, 1, InetAddress.getByName("localhost"));
  }        
  public class Connector implements Lifecycle, MBeanRegistration{
  protected Service service = null;
  /**
  * The Container used for processing requests received by this Connector.
  */
  protected Container container = null;
  /**
  * Use "/" as path for session cookies ?
  */
  protected boolean emptySessionPath = false;
  /**
  * The redirect port for non-SSL to SSL redirects.
  */
  protected int redirectPort = 443;
  /**
  * The request scheme that will be set on all requests received through this connector.
  */
  protected String scheme = "http";
  /**
  * Maximum size of a POST which will be automatically parsed by the
  * container. 2MB by default.
  */
  protected int maxPostSize = 2 * 1024 * 1024;
  /**
  * Maximum size of a POST which will be saved by the container
  * during authentication可信的. 4kB by default
  */
  protected int maxSavePostSize = 4 * 1024;
  /**
  * The background thread.
  */
  protected Thread thread = null;
  /**
  * Coyote Protocol handler class name.
  * Defaults to the Coyote HTTP/1.1 protocolHandler.
  */
  protected String protocolHandlerClassName =
  "org.apache.coyote.http11.Http11Protocol";
  /**
  * Coyote protocol handler.
  */
  protected ProtocolHandler protocolHandler = null;
  /**
  * Coyote adapter.
  */
  protected Adapter adapter = null;
  /**
  * Mapper.
  */
  protected Mapper mapper = new Mapper();
  /**
  * Mapper listener.
  */
  protected MapperListener mapperListener = new MapperListener(mapper, this);
  /**
  * URI encoding.
  */
  protected String URIEncoding = null;
  /**
  * URI encoding as body.
  */
  protected boolean useBodyEncodingForURI = false;
  /**
  * Set the Coyote protocol which will be used by the connector.
  */
  public void setProtocol(String protocol) {
  if (AprLifecycleListener.isAprAvailable()) {
  if ("HTTP/1.1".equals(protocol)) {
  setProtocolHandlerClassName
  ("org.apache.coyote.http11.Http11AprProtocol");
  } else if ("AJP/1.3".equals(protocol)) {
  setProtocolHandlerClassName
  ("org.apache.coyote.ajp.AjpAprProtocol");
  } else if (protocol != null) {
  setProtocolHandlerClassName(protocol);
  } else {
  setProtocolHandlerClassName
  ("org.apache.coyote.http11.Http11AprProtocol");
  }
  } else {
  if ("HTTP/1.1".equals(protocol)) {
  setProtocolHandlerClassName
  ("org.apache.coyote.http11.Http11Protocol");
  } else if ("AJP/1.3".equals(protocol)) {
  setProtocolHandlerClassName
  ("org.apache.jk.server.JkCoyoteHandler");
  } else if (protocol != null) {
  setProtocolHandlerClassName(protocol);
  }
  }
  }
  /**
  * Create (or allocate) and return a Request object suitable for
  * specifying the contents of a Request to the responsible Container.
  org.apache.catalina.connector.Request
  */
  public Request createRequest() {
  Request request = new Request();
  request.setConnector(this);
  return (request);
  }
  /**
  * Create (or allocate) and return a Response object suitable for
  * receiving the contents of a Response from the responsible Container.
  */
  public Response createResponse() {
  Response response = new Response();
  response.setConnector(this);
  return (response);
  }
  // 省略------------------------------------------------------ Lifecycle Methods
  // 省略-------------------- JMX registration  --------------------
  /**
  * Shutdown hook which will perform a clean shutdown of Catalina if needed.
  */
  protected class CatalinaShutdownHook extends Thread {
  public void run() {
  try {
  if (getServer() != null) {
  Catalina.this.stop();
  }
  } catch (Throwable ex) {
  log.error(sm.getString("catalina.shutdownHookFail"), ex);
  } finally {
  // If JULI is used, shut JULI down *after* the server shuts down
  // so log messages aren't lost
  LogManager logManager = LogManager.getLogManager();
  if (logManager instanceof ClassLoaderLogManager) {
  ((ClassLoaderLogManager) logManager).shutdown();
  }
  }
  }
  }
  }         
  public interface Engine extends Container {
  public String getDefaultHost();
  public void setDefaultHost(String defaultHost);
  public String getJvmRoute();
  public void setJvmRoute(String jvmRouteId);
  public Service getService();
  public void setService(Service service);
  }        
  public class StandardEngine extends ContainerBase implements Engine{}        
  public class StandardHost extends ContainerBase implements Host{
  /**
  * The set of aliases for this Host.
  */
  private String[] aliases = new String[0];
  private final Object aliasesLock = new Object();
  /**
  * The application root for this Host.
  */
  private String appBase = "webapps";
  /**
  * The auto deploy flag for this Host.
  */
  private boolean autoDeploy = true;
  /**
  * The Java class name of the default context configuration class
  * for deployed web applications.
  */
  private String configClass =
  "org.apache.catalina.startup.ContextConfig";
  /**
  * The Java class name of the default Context implementation class for
  * deployed web applications.
  */
  private String contextClass =
  "org.apache.catalina.core.StandardContext";
  /**
  * Attribute value used to turn on/off XML namespace awarenes.
  */
  private boolean xmlNamespaceAware = false;
  /**
  * Track the class loaders for the child web applications so memory leaks漏洞
  * can be detected.
  */
  private Map<ClassLoader, String> childClassLoaders =
  new WeakHashMap<ClassLoader, String>();
  ...其他的field省略
  }         
  /**
  * Standard implementation of the <b>Context</b> interface.  Each
  * child container must be a Wrapper implementation to process the
  * requests directed to a particular servlet.
  */
  public class StandardContext extends ContainerBase implements Context, Serializable, NotificationEmitter{        
  /**
  * The ServletContext implementation associated with this Context.
  */
  protected transient ApplicationContext context = null;
  /**
  * Compiler classpath to use.
  */
  private String compilerClasspath = null;
  /**
  * Should we attempt to use cookies for session id communication?
  */
  private boolean cookies = true;
  /**
  * Should we allow the <code>ServletContext.getContext()</code> method
  * to access the context of other web applications in this server?
  */
  private boolean crossContext = false;
  /**
  * The MIME mappings for this web application, keyed by extension.
  */
  private HashMap mimeMappings = new HashMap();
  /**
  * The servlet mappings for this web application, keyed by
  * matching pattern.
  */
  private HashMap servletMappings = new HashMap();
  /**
  * The welcome files for this application.
  */
  private String welcomeFiles[] = new String[0];
  /**
  * Cache object max size in KB.
  */
  protected int cacheObjectMaxSize = 512; // 512K
  /**
  * Cache TTL in ms.
  */
  protected int cacheTTL = 5000;
  /**
  * The domain to use for session cookies. <code>null</code> indicates that
  * the domain is controlled by the application.
  */
  private String sessionCookieDomain;
  /**
  * The path to use for session cookies. <code>null</code> indicates that
  * the path is controlled by the application.
  */
  private String sessionCookiePath;
  /**
  * The name to use for session cookies. <code>null</code> indicates that
  * the name is controlled by the application.
  */
  private String sessionCookieName;
  }            
  /**
  * Standard implementation of the <b>Wrapper</b> interface that represents
  * an individual servlet definition.  No child Containers are allowed, and
  * the parent Container must be a Context.
  */
  public interface Wrapper extends Container{} 
  public class StandardWrapper extends ContainerBase implemen ts ServletConfig, Wrapper, NotificationEmitter {
  /**
  * The (single) initialized instance of this servlet.
  */
  protected Servlet instance = null;
  /**
  * The context-relative URI of the JSP file for this servlet.
  */
  protected String jspFile = null;
  }        
  /**
  * Standard implementation of <code>ServletContext</code> that represents
  * a web application's execution environment.  An instance of this class is
  * associated with each instance of <code>StandardContext</code>.
  */
  public class ApplicationContext implements ServletContext {
  /**
  * The Context instance with which we are associated.
  */
  private StandardContext context = null;
  /**
  * Base path.
  */
  private String basePath = null;
  public String getRealPath(String path) {
  File file = new File(basePath, path);
  return (file.getAbsolutePath());
  }
  /**
  * Return a <code>RequestDispatcher</code> instance that acts as a
  * wrapper for the resource at the given path.  The path must begin
  * with a "/" and is interpreted as relative to the current context root.
  *
  * @param path The path to the desired resource.
  */
  public RequestDispatcher getRequestDispatcher(String path) {}
  protected StandardContext getContext() {
  return this.context;
  }
  }        
  /**
  * Startup event listener for a <b>Context</b> that configures the properties
  * of that Context, and the associated defined servlets.
  */
  public class ContextConfig implements LifecycleListener {
  /**
  * The Context we are associated with.
  */
  protected Context context = null;
  /**
  * The default web application's context file location.
  */
  protected String defaultContextXml = null;
  /**
  * The default web application's deployment descriptor location.
  */
  protected String defaultWebXml = null;
  }        
  org.apache.catalina.core.ApplicationHttpRequest 
  extends javax.servlet.http.HttpServletRequestWrapper 
  extends javax.servlet.ServletRequestWrapper
  //作用类似javaBean
  public final class org.apache.coyote.Request{
  private int serverPort = -1;
  private UDecoder urlDecoder = new UDecoder();
  private MimeHeaders headers = new MimeHeaders();
  private MessageBytes uriMB = MessageBytes.newInstance();        
  }
  org.apache.catalina.connector.Request implements HttpServletRequest{
  protected org.apache.coyote.Request coyoteRequest
  public InputStream getStream() {
  if (inputStream == null) {
  inputStream = new CoyoteInputStream(inputBuffer);
  }
  return inputStream;
  }
  protected int readPostBody(byte body[], int len)throws IOException {
  int inputLen = getStream().read(body, offset, len - offset);
  }
  /**
  * Return the session associated with this Request, creating one
  * if necessary and requested.
  */
  public HttpSession getSession(boolean create) {
  Session session = doGetSession(create);
  if (session != null) {
  return session.getSession();
  } else {
  return null;
  }
  }
  /**
  * Change the ID of the session that this request is associated with. There
  * are several things that may trigger an ID change. These include moving
  * between nodes in a cluster and session fixation prevention during the
  * authentication process.
  */
  public void changeSessionId(String newSessionId) {...}
  protected Session doGetSession(boolean create) {
  // Attempt to reuse session id if one was submitted in a cookie
  // Do not reuse the session id if it is from a URL, to prevent possible
  // phishing attacks
  if (connector.getEmptySessionPath() 
  && isRequestedSessionIdFromCookie()) {
  session = manager.createSession(getRequestedSessionId());
  } else {
  //createSession最终会调用StandardSession的构造。
  session = manager.createSession(null);
  }
  // Creating a new session cookie based on that session
  if ((session != null) && (getContext() != null)
  && getContext().getCookies()) {
  String scName = context.getSessionCookieName();
  if (scName == null) {
  scName = Globals.SESSION_COOKIE_NAME;
  }
  Cookie cookie = new Cookie(scName, session.getIdInternal());
  configureSessionCookie(cookie);
  //save到浏览器内存
  response.addSessionCookieInternal(cookie, context.getUseHttpOnly());
  }
  }
  /**
  * Parse accept-language header value.
  */
  protected void parseLocalesHeader(String value) {...}
  public String getParameter(String name) {...}
  }
  Connector通过8080端口连接coyote http1.1,通过8009连接coyote AJP1.3
  ServerCookie、Cookies与javax.servlet.http.Cookie的联系?
  cookie如何实现的?还有浏览器的。如何获取解析cookie、url重写过的sessionid      
  /**
  *  Server-side cookie representation.
  *  Allows recycling and uses MessageBytes as low-level
  *  representation ( and thus the byte-> char conversion can be delayed
  *  until we know the charset ).
  *  Tomcat.core uses this recyclable object to represent cookies,
  *  and the facade will convert it to the external representation.
  */
  public class org.apache.tomcat.util.http.ServerCookie implements Serializable {...}        
  /**
  * A collection of cookies - reusable and tuned for server side performance.
  * Based on RFC2965 ( and 2109 )
  */
  public final class org.apache.tomcat.util.http.Cookies { 
  ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];
  /** Register a new, unitialized cookie. Cookies are recycled, and
  *  most of the time an existing ServerCookie object is returned.
  *  The caller can set the name/value and attributes for the cookie
  */
  public ServerCookie addCookie() {
  if( cookieCount >= scookies.length  ) {
  ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];
  System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
  scookies=scookiesTmp;
  }
  ServerCookie c = scookies[cookieCount];
  if( c==null ) {
  c= new ServerCookie();
  scookies[cookieCount]=c;
  }
  cookieCount++;
  return c;
  }
  /** Add all Cookie found in the headers of a request.
  */
  public  void processCookies( MimeHeaders headers ) {...
  /**
  * Parses a cookie header after the initial "Cookie:"
  * [WS][$]token[WS]=[WS](token|QV)[;|,]
  * RFC 2965
  * JVK
  */
  public final void processCookieHeader(byte bytes[], int off, int len){...}
  }
  //为什么要多这个对象StandardSessionFacade?????
  public class StandardSessionFacade implements HttpSession {
  private HttpSession session = null;
  }
  /**
  * Standard implementation of the <b>Session</b> interface.  This object is
  * serializable, so that it can be stored in persistent storage or transferred
  * to a different JVM for distributable session support.
  * If you add fields to this class, you must
  * make sure that you carry them over in the read/writeObject methods so
  * that this class is properly serialized.
  */
  public class StandardSession implements HttpSession, Session, Serializable {
  /**
  * The time this session was created, in milliseconds since midnight,
  * January 1, 1970 GMT.
  */
  protected long creationTime = 0L;
  /**
  * Return the <code>HttpSession</code> for which this object
  * is the facade.
  */
  protected static HttpSessionContext sessionContext = null; 
  protected transient StandardSessionFacade facade = null;
  public HttpSession getSession() {
  return (facade);
  }
  /**
  * The HTTP session context associated with this session.
  */
  /**
  * Inform通知 the listeners about the new session.此类中有多种多个event、listener
  */
  public void tellNew() {...}
  /**
  * Update the accessed time information for this session.  This method
  * should be called by the context when a request comes in for a particular
  * session, even if the application does not reference it.
  * 会被invokeHttp11NioProcessor之类的invoke(request, response)调用;
  */
  public void access() {...}
  }   
  /**
  * Standard implementation of the <b>Server</b> interface, available for use
  * (but not required) when deploying and starting Catalina.
  *
  * @author Craig R. McClanahan
  * @version $Id: StandardServer.java 1066492 2011-02-02 15:02:49Z kkolinko $
  */
  public final class StandardServer implements Lifecycle, Server, MBeanRegistration {
  awaitSocket = new ServerSocket(port, 1,InetAddress.getByName("localhost"));
  }   
  好多类中都会创建ServerSocket比如下面这几个:                
  org\apache\coyote\http11\Http11Protocol.java
  org\apache\jk\common\ChannelNioSocket.java                
  ServerSocketChannel ssc = ServerSocketChannel.open();
  org\apache\jk\common\ChannelSocket.java
  ServerSocket sSocket = new ServerSocket( i, backlog );
  org\apache\tomcat\util\net\JIoEndpoint.java
  serverSocket = serverSocketFactory.createSocket(port, backlog);
  org\apache\tomcat\util\net\NioEndpoint.java                
  serverSock = ServerSocketChannel.open();
  其实创建一个 session 并不耗什么资源,无非就是一个空的map,就是别往里面塞太多的东西,尤其是在集群环境下,会增加同步的负担。                  
  在文件《D:\study\src_zip\org\apache\catalina\core\StandardServer.java》中查找:"getInputStream"
  stream = socket.getInputStream();   

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-330090-1-1.html 上篇帖子: 一台电脑安装多个tomcat 下篇帖子: How to rotate tomcat logs
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表