Tomcat源码系列1--Tomcat启动流程1

文章分类:Java编程

最近在看Tomcat的源码,下面用博客记下看源码的一些心得。

Tomcat是从org.apache.catalina.startup.Bootstrap#main()开始启动. 大致分为三个步骤,即init、load和start。代码如下:

Java代码  
  1. public   static   void  main(String args[]) {
  2. try  {
  3. // Attempt to load JMX class
  4. new  ObjectName( "test:foo=bar" );
  5. } catch  (Throwable t) {
  6. System.out.println(JMX_ERROR_MESSAGE);
  7. try  {
  8. // Give users some time to read the message before exiting
  9. Thread.sleep(5000 );
  10. } catch  (Exception ex) {
  11. }
  12. return ;
  13. }
  14. if  (daemon ==  null ) {
  15. daemon = new  Bootstrap();
  16. try  {
  17. daemon.init();   ★1
  18. } catch  (Throwable t) {
  19. t.printStackTrace();
  20. return ;
  21. }
  22. }
  23. try  {
  24. String command = "start" ;
  25. if  (args.length >  0 ) {
  26. command = args[args.length - 1 ];
  27. }
  28. if  (command.equals( "startd" )) {
  29. args[0 ] =  "start" ;
  30. daemon.load(args);
  31. daemon.start();
  32. } else   if  (command.equals( "stopd" )) {
  33. args[0 ] =  "stop" ;
  34. daemon.stop();
  35. } else   if  (command.equals( "start" )) {
  36. daemon.setAwait(true );
  37. daemon.load(args);   ★2
  38. // 反射调用Catalina的start方法
  39. daemon.start();        ★3
  40. } else   if  (command.equals( "stop" )) {
  41. daemon.stopServer(args);
  42. }
  43. } catch  (Throwable t) {
  44. t.printStackTrace();
  45. }
  46. }
public static void main(String args[]) { try { // Attempt to load JMX class new ObjectName("test:foo=bar"); } catch (Throwable t) { System.out.println(JMX_ERROR_MESSAGE); try { // Give users some time to read the message before exiting Thread.sleep(5000); } catch (Exception ex) { } return; } if (daemon == null) { daemon = new Bootstrap(); try { daemon.init();   ★1 } catch (Throwable t) { t.printStackTrace(); return; } } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[0] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[0] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args);   ★2 // 反射调用Catalina的start方法 daemon.start();        ★3 } else if (command.equals("stop")) { daemon.stopServer(args); } } catch (Throwable t) { t.printStackTrace(); } }  

从以上可以很清楚的看出tomcat是通过参数的不同进行相应的命令调用。
★1 启动、初始化(加载类)
启动之前要进行相应的init()初始化,进行相应的环境设置以及包的加,以下是init()方法。(org.apache.catalina.startup.Bootstrap.init())

Java代码  
  1. public   void  init()
  2. throws  Exception
  3. {
  4. setCatalinaHome();//设置Catalina安装目录
  5. setCatalinaBase();//设置Catalina工作目录
  6. initClassLoaders();//加载jar包
  7. // 将classload设置进线程,以便我们使用时进行调用
  8. Thread.currentThread().
  9. setContextClassLoader(catalinaLoader);
  10. SecurityClassLoad.securityClassLoad(catalinaLoader);
  11. // 加载启动类和调用它的process方法
  12. if  (log.isDebugEnabled())
  13. log.debug("Loading startup class" );
  14. Class startupClass =
  15. catalinaLoader.loadClass
  16. ("org.apache.catalina.startup.Catalina" );
  17. Object startupInstance = startupClass.newInstance();
  18. // 设置共享扩张类加载器
  19. if  (log.isDebugEnabled())
  20. log.debug("Setting startup class properties" );
  21. String methodName = "setParentClassLoader" ;
  22. Class paramTypes[] = new  Class[ 1 ];
  23. paramTypes[0 ] = Class.forName( "java.lang.ClassLoader" );
  24. Object paramValues[] = new  Object[ 1 ];
  25. paramValues[0 ] = sharedLoader;
  26. Method method =
  27. startupInstance.getClass().getMethod(methodName,
  28. paramTypes);
  29. method.invoke(startupInstance, paramValues);
  30. catalinaDaemon = startupInstance;
  31. }
public void init() throws Exception { setCatalinaHome();//设置Catalina安装目录 setCatalinaBase();//设置Catalina工作目录 initClassLoaders();//加载jar包 // 将classload设置进线程,以便我们使用时进行调用       Thread.currentThread(). setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // 加载启动类和调用它的process方法 if (log.isDebugEnabled()) log.debug("Loading startup class"); Class startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // 设置共享扩张类加载器 if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; } 

在加载jar的时候,需要初始化classloader,代码如下:(org.apache.catalina.startup.Bootstrap)

Java代码  
  1. private   void  initClassLoaders() {
  2. try  {
  3. commonLoader = createClassLoader("common" ,  null );
  4. catalinaLoader= createClassLoader("server" , commonLoader);
  5. sharedLoader = createClassLoader("shared" , commonLoader);
  6. } catch  (Throwable t) {
  7. log.error("Class loader creation threw exception" , t);
  8. System.exit(1 );
  9. }
  10. }
private void initClassLoaders() { try { commonLoader = createClassLoader("common", null); catalinaLoader= createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { log.error("Class loader creation threw exception", t); System.exit(1); } }

tomcat中的加载方式是:
|-------commonLoader (common)-> System Loader
|-------sharedLoader (shared)-> commonLoader -> System Loader
|-------catalinaLoader(server) -> commonLoader -> System Loader

Common 是公共类加载器,负责加载tomcat内部和web应用程序可以看到的类(%CATALINA_HOME%/bin/common下的jar文 件),Catalina负责加载的是tomcat内部使用的类(%CATALINA_HOME%/server下的jar文件),这些类对web应用程序 不可见。Shared负责加载的是web应用程序之间共享的类(%CATALINA_BASE%/shared下的jar文件),这些类对于tomcat 内部是不可见的。如果%CATALINA_HOME%/conf/catalina.Properties中没有指定Common的搜索路径,则用当前的 类的类加载器即系统类加载器作为Common。

★2 装载相应的资源
下面主要讲解tomcat的load()方法。下图是Catalina.load方法的时序图。


 
(1) 从上面的时序图可以看出首先调用Catalina类的load()方法,具体代码如下:
(org.apache.catalina.startup.Catalina)。

Java代码  
  1. public   void  load() {
  2. initDirs();
  3. // Before digester - it may be needed
  4. initNaming();
  5. // Create and execute our Digester
  6. Digester digester = createStartDigester();
  7. try  {
  8. inputSource.setByteStream(inputStream);
  9. digester.push(this );
  10. digester.parse(inputSource); //对server.xml进行解析
  11. inputStream.close();
  12. }
  13. ......
  14. // Start the new server
  15. if  (server  instanceof  Lifecycle) {
  16. try  {
  17. server.initialize();  //server初始化工作
  18. } catch  (LifecycleException e) {
  19. log.error("Catalina.start" , e);
  20. }
  21. }
  22. long  t2 = System.currentTimeMillis();
  23. log.info("Initialization processed in "  + (t2 - t1) +  " ms" );
  24. }
public void load() { initDirs(); // Before digester - it may be needed initNaming(); // Create and execute our Digester Digester digester = createStartDigester(); try { inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); //对server.xml进行解析 inputStream.close(); } ...... // Start the new server if (server instanceof Lifecycle) { try { server.initialize();  //server初始化工作 } catch (LifecycleException e) { log.error("Catalina.start", e); } } long t2 = System.currentTimeMillis(); log.info("Initialization processed in " + (t2 - t1) + " ms"); } 

(2) 在上面的load()方法中需要进行server的初始化工作,下图为Catalina.initialize的时序图,从图中可以看出server初始化所完成的工作。

至此,load方法结束,初期化的工作结束,下面开始进入start方法。

★3 容器启动
容器启动时,会调用Catalina.start(),下图为它的时序图。从图中可以看出StandardService的start方法被调用后会分别对Container和Connector进行start方法的调用。

1. Bootstrap调用Catalina的start方法
Catalina.start()方法(org.apache.catalina.startup.Catalina.start())

Java代码  
  1. public   void  start() {
  2. // 启动server
  3. if  (server  instanceof  Lifecycle) {
  4. try  {
  5. ((Lifecycle) server).start();
  6. ......
  7. }
    public void start() { // 启动server if (server instanceof Lifecycle) { try { ((Lifecycle) server).start(); ...... }

2. Catalina调用StandardServer的start方法
StandardServer.start() (org.apache.catalina.core.StandardServer.start() )

Java代码  
  1. public   void  start()  throws  LifecycleException {
  2. synchronized  (services) {
  3. for  ( int  i =  0 ; i < services.length; i++) {
  4. if  (services[i]  instanceof  Lifecycle)
  5. ((Lifecycle) services[i]).start();
  6. }
  7. }
public void start() throws LifecycleException {       synchronized (services) { for (int i = 0; i < services.length; i++) { if (services[i] instanceof Lifecycle) ((Lifecycle) services[i]).start(); }
} 

3. StandardServer调用StandardService的start方法

Java代码  
  1. org.apache.catalina.core.StandardService.start() )
  2. public   void  start()  throws  LifecycleException {
  3. if  (container !=  null ) {
  4. synchronized  (container) {
  5. if  (container  instanceof  Lifecycle) {
  6. //  standardEngine的启动
  7. ((Lifecycle) container).start();
  8. }
  9. }
  10. //两个connector的启动,8080和8009
  11. synchronized  (connectors) {
  12. for  ( int  i =  0 ; i < connectors.length; i++) {
  13. if  (connectors[i]  instanceof  Lifecycle)
  14. ((Lifecycle) connectors[i]).start();
  15. }
  16. }
  17. }
org.apache.catalina.core.StandardService.start() ) public void start() throws LifecycleException { if (container != null) { synchronized (container) { if (container instanceof Lifecycle) { //  standardEngine的启动 ((Lifecycle) container).start(); } } //两个connector的启动,8080和8009   synchronized (connectors) {   for (int i = 0; i < connectors.length; i++) {   if (connectors[i] instanceof Lifecycle)   ((Lifecycle) connectors[i]).start();   }   }
} 

以上StandardService.start()方法主要实现了两个功能,standardEngine的启动和connector的启动,下面分别来介绍。

Tomcat源码系列2--Tomcat启动流程2

文章分类:Java编程

下面是standardEngine 的启动和 connector 的启动

● standardEngine的启动
(1) 首先是StandardEngine.start()被调用

Java代码  
  1. public   void  start()  throws  LifecycleException {
  2. // Standard container startup
  3. //进行logger,manager,cluster,realm,resource的启动
  4. super .start();
  5. }
public void start() throws LifecycleException { // Standard container startup   //进行logger,manager,cluster,realm,resource的启动   super.start();
}

(2) super.start()--->org.apache.catalina.core.ContainerBase#start()

Java代码  
  1. public   synchronized   void  start()  throws  LifecycleException {
  2. //(省略)  server.xml中配置应用组件的启动
  3. //StandardHost容器的启动,
  4. Container children[] = findChildren();
  5. for  ( int  i =  0 ; i < children.length; i++) {
  6. if  (children[i]  instanceof  Lifecycle)
  7. ((Lifecycle) children[i]).start();
  8. }
  9. //StandardPipeline的启动(容器与容器间的管道)
  10. if  (pipeline  instanceof  Lifecycle)
  11. ((Lifecycle) pipeline).start();
  12. }
public synchronized void start() throws LifecycleException {
//(省略)  server.xml中配置应用组件的启动
//StandardHost容器的启动,   Container children[] = findChildren();   for (int i = 0; i < children.length; i++) {   if (children[i] instanceof Lifecycle)   ((Lifecycle) children[i]).start();   }     //StandardPipeline的启动(容器与容器间的管道)   if (pipeline instanceof Lifecycle)   ((Lifecycle) pipeline).start();
} 

(3) StandardHost.start()被调用

Java代码  
  1. public   synchronized   void  start()  throws  LifecycleException {
  2. //返回到以上的containerBase#start执行pipeline
  3. super .start();
  4. }
public synchronized void start() throws LifecycleException {
//返回到以上的containerBase#start执行pipeline   super.start();
}

(4) StandardPipeline#start

Java代码  
  1. public   synchronized   void  start()  throws  LifecycleException {
  2. // 将会调用HostConfig#start方法
  3. lifecycle.fireLifecycleEvent(START_EVENT, null );
  4. // Notify our interested LifecycleListeners
  5. lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null );
  6. }
public synchronized void start() throws LifecycleException { // 将会调用HostConfig#start方法   lifecycle.fireLifecycleEvent(START_EVENT, null);   // Notify our interested LifecycleListeners   lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}

(5)  HostConfig#start

Java代码  
  1. public   void  start() {
  2. //部暑webapps
  3. deployApps();
  4. }
public void start() {  //部暑webapps   deployApps();            } 

(6) HostConfig#deployApps

Java代码  
  1. protected   void  deployApps() {
  2. File appBase = appBase();
  3. File configBase = configBase();
  4. // Deploy XML descriptors from configBase
  5. deployDescriptors(configBase, configBase.list());
  6. // Deploy WARs, and loop if additional descriptors are found
  7. deployWARs(appBase, appBase.list());
  8. // Deploy expanded folders
  9. deployDirectories(appBase, appBase.list());
  10. }
   protected void deployApps() {   File appBase = appBase();   File configBase = configBase();   // Deploy XML descriptors from configBase   deployDescriptors(configBase, configBase.list());   // Deploy WARs, and loop if additional descriptors are found   deployWARs(appBase, appBase.list());   // Deploy expanded folders   deployDirectories(appBase, appBase.list());             }

(7) deployWARs

Java代码  
  1. protected   void  deployWARs(File appBase, String[] files) {
  2. ……
  3. deployWAR(contextPath, dir, file);
  4. }
protected void deployWARs(File appBase, String[] files) {
……
deployWAR(contextPath, dir, file);          } 

(8) deployWAR

Java代码  
  1. protected   void  deployWAR(String contextPath, File war, String file) {
  2. if  (context  instanceof  Lifecycle) {
  3. // (省略)
  4. Class clazz = Class.forName(host.getConfigClass());
  5. LifecycleListener listener =
  6. (LifecycleListener) clazz.newInstance();
  7. ((Lifecycle) context).addLifecycleListener(listener);
  8. }
  9. context.setPath(contextPath);
  10. context.setDocBase(file);
  11. //以下这一步跟进去,,StandardContext的启动
  12. host.addChild(context);
  13. }
protected void deployWAR(String contextPath, File war, String file) {
if (context instanceof Lifecycle) {   // (省略) Class clazz = Class.forName(host.getConfigClass());   LifecycleListener listener =   (LifecycleListener) clazz.newInstance();   ((Lifecycle) context).addLifecycleListener(listener);   }   context.setPath(contextPath);   context.setDocBase(file);   //以下这一步跟进去,,StandardContext的启动   host.addChild(context);         }

(9) StandardContext#start
在Context的启动过程中,主要完成了以下任务。
----------------------------------------------------------------------------------------------------------------------
a) 设置web app的具体目录webappResources。 
b) postWorkDirectory (),创建临时文件目录。Tomcat下面有一个work目录,用来存放临时文件。
c) 触发START_EVENT事件监听,在这个事件监听里面会启动ContextConfig的start()事件,ContextConfig是用来配置web.xml的。
d) 为context创建welcome files,通常是这三个启动文件:index.html、index.htm、index.jsp
e) 配置filter
f) 启动带有<load-on-startup>的Servlet。
g) 注册JMX。
----------------------------------------------------------------------------------------------------------------------
至此,Container启动完毕,下面是connector的启动。

● connector的启动
(1) org.apache.catalina.connector.Connector.start()

Java代码  
  1. public   void  start()  throws  LifecycleException {
  2. // Http11Protocol的启动
  3. protocolHandler.start();
  4. }
public void start() throws LifecycleException { // Http11Protocol的启动 protocolHandler.start();
}

(2) Http11Protocol#start

Java代码  
  1. public   void  start()  throws  Exception {
  2. try  {
  3. //到了终点的启动
  4. endpoint.start();
  5. } catch  (Exception ex) {
  6. log.error(sm.getString("http11protocol.endpoint.starterror" ), ex);
  7. throw  ex;
  8. }
public void start() throws Exception {
try {   //到了终点的启动   endpoint.start();   } catch (Exception ex) {   log.error(sm.getString("http11protocol.endpoint.starterror"), ex);   throw ex;   }

(3) JIoEndPoint#start

Java代码  
  1. public   void  start()
  2. throws  Exception {
  3. for  ( int  i =  0 ; i < acceptorThreadCount; i++) {
  4. //这里的acceptor是一个线程,里面是一个serversocket的启动
  5. Thread acceptorThread = new  Thread( new  Acceptor(), getName() +  "-Acceptor-"  + i);
  6. acceptorThread.setPriority(threadPriority);
  7. acceptorThread.setDaemon(daemon);
  8. acceptorThread.start();
  9. }
  10. }
public void start()   throws Exception {            for (int i = 0; i < acceptorThreadCount; i++) {   //这里的acceptor是一个线程,里面是一个serversocket的启动   Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);   acceptorThread.setPriority(threadPriority);   acceptorThread.setDaemon(daemon);   acceptorThread.start();   }   }

(4) Acceptor#run

Java代码  
  1. public   void  run() {
  2. // Accept the next incoming connection from the server socket
  3. try  {
  4. //这里进行了accept(),等待客户端消息,进行接收
  5. Socket socket = serverSocketFactory.acceptSocket(serverSocket);
  6. serverSocketFactory.initSocket(socket);
  7. // Hand this socket off to an appropriate processor
  8. if  (!processSocket(socket)) {
  9. // Close socket right away
  10. try  {
  11. socket.close();
  12. } catch  (IOException e) {
  13. // Ignore
  14. }
  15. }
  16. }catch  ( IOException x ) {
  17. if  ( running ) log.error(sm.getString( "endpoint.accept.fail" ), x);
  18. } catch  (Throwable t) {
  19. log.error(sm.getString("endpoint.accept.fail" ), t);
  20. }
  21. }
public void run() {
// Accept the next incoming connection from the server socket   try {   //这里进行了accept(),等待客户端消息,进行接收   Socket socket = serverSocketFactory.acceptSocket(serverSocket);   serverSocketFactory.initSocket(socket);   // Hand this socket off to an appropriate processor   if (!processSocket(socket)) {   // Close socket right away   try {   socket.close();   } catch (IOException e) {   // Ignore   }   }   }catch ( IOException x ) {   if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);   } catch (Throwable t) {   log.error(sm.getString("endpoint.accept.fail"), t);   }
} 

至此Connector.start方法调用完毕。整个server启动完毕。

Tomcat源码系列3--Tomcat请求处理的流程

文章分类:Java编程

本次讲解一下Tomcat请求处理的流程,不当之处还请comment。

一. Tomcat 总体结构
Tomcat采用模块化管理,下面是 Tomcat 的总体结构图:


 
从上图中可以看出 Tomcat 的核心是两个组件:Connector 和 Container。下面是一些概念的介绍。
① Server
一个server代表了整个catalina servlet容器,在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令)。
② Service
Service是由一个或多个Connector与一个Engine的组合。
③ Connector
Connector将在某个指定的端口上监听客户的请求,把从socket传递过来的数据,封装成Request,传递给Engine来处理,并从Engine处获得响应并返回给客户。
Tomcat通常会用到两种Connector:
a) Http Connector 在端口8080处侦听来自客户browser的http请求。
b) AJP Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。

二、请求处理过程解析
1. Connector处理请求
Connector处理请求的流程大致如下:


 
Connector组件启动后,会侦听相关的端口的客户端请求。
(1) 接受一个新的连接请求(org.apache.tomcat.util.net.TcpWorkerThread)

Java代码  
  1. void  runIt(Object[] perThrData){
  2. Socket s = null ;
  3. try  {
  4. s = endpoint.acceptSocket();  //获取一个请求
  5. } finally  {
  6. if  (endpoint.isRunning()) {
  7. endpoint.tp.runIt(this );
  8. // 此处启动另一个TcpWorkerTread去接受其他请求,此线程处理已接受的请求
  9. }
  10. }
  11. TcpConnection con = null ;
  12. con = (TcpConnection) perThrData[0 ];
  13. con.setEndpoint(endpoint);
  14. con.setSocket(s);endpoint.getConnectionHandler().processConnection(con,(Object[]) perThrData[1 ]);
  15. }
void runIt(Object[] perThrData){ Socket s = null; try { s = endpoint.acceptSocket();  //获取一个请求 } finally { if (endpoint.isRunning()) { endpoint.tp.runIt(this); // 此处启动另一个TcpWorkerTread去接受其他请求,此线程处理已接受的请求 } }                 TcpConnection con = null; con = (TcpConnection) perThrData[0]; con.setEndpoint(endpoint); con.setSocket(s);endpoint.getConnectionHandler().processConnection(con,(Object[]) perThrData[1]);
}

(2) 新接收的请求被传到Http11ConnectionHandler中处理。(org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler)

Java代码  
  1. void  processConnection(TcpConnection connection, Object[] thData){
  2. Http11Processor  processor=null ;
  3. processor=(Http11Processor)thData[Http11Protocol.THREAD_DATA_PROCESSOR];
  4. socket=connection.getSocket();
  5. InputStream in = socket.getInputStream();
  6. OutputStream out = socket.getOutputStream();
  7. processor.setSocket(socket );
  8. processor.process(in, out);
  9. //processor是org.apache.coyote.http11.Http11Processor 的 一个实例
  10. }
void processConnection(TcpConnection connection, Object[] thData){     Http11Processor  processor=null; processor=(Http11Processor)thData[Http11Protocol.THREAD_DATA_PROCESSOR];   socket=connection.getSocket();                      InputStream in = socket.getInputStream();   OutputStream out = socket.getOutputStream(); processor.setSocket(socket ); processor.process(in, out);
//processor是org.apache.coyote.http11.Http11Processor 的 一个实例
}

(3) 在 Http11Processor 中处理 http11 协议相关的信息(org.apache.coyote.http11.Http11Processor)

Java代码  
  1. void  process(InputStream input, OutputStream output)  throws  IOException{
  2. ~~略~~
  3. inputBuffer.setInputStream(input);
  4. outputBuffer.setOutputStream(output);
  5. inputBuffer.parseHeaders();
  6. //http11 协议头在此方法中被取出
  7. adapter.service(request, response);
  8. //adapter 是org.apache.catalina.connector.CoyoteAdapter 的 一个实例
  9. }
void process(InputStream input, OutputStream output) throws IOException{ ~~略~~ inputBuffer.setInputStream(input); outputBuffer.setOutputStream(output); inputBuffer.parseHeaders(); //http11 协议头在此方法中被取出 adapter.service(request, response);    //adapter 是org.apache.catalina.connector.CoyoteAdapter 的 一个实例
}

接下来的流程交由容器进行处理。
2. 容器处理请求
容器交由Pipeline处理,这个Pipeline里面会放置一些vavle,请求沿着pipeline传递下去并且vavle对其进行相关的处理。比如说日志等,valve还可以自定义,具体需要查看server.xml配置文件。相关类图如下:


 
Tomcat 的主要处理组件Engine、Host、Context和Wrapper的实现都会实现Pipeline接口,实际对请求的处理是一个 Adpater,Tomcat中Adapter的实现是CoyoteAdapter,因此容器请求处理的入口是CoyoteAdapter的 service方法。
1. CoyoteAdapter.service
   --组装好请求处理链
   --StandardEngine. getPipeline().getFirst().invoke(request, response);
       --StandardEngineValve.invoke
2. StandardEngineValve.invoke
   --Host.getPipeline().getFirst().invoke(request, response);
      --StandardHostValve.invoke
3. StandardHostValve.invoke
  --Context. getPipeline().getFirst().invoke(request, response);
     --StandardContextValve.invoke
4. StandardContextValve.invoke
    --ServletRequestListener.requestInitialized
    --Wrapper.getPipeline().getFirst().invoke(request, response);
          --StandardWrapperValve.invoke
    -- ServletRequestListener.requestDestroyed
5. StandardWrapperValve.invoke
    --组装Filter+Servlet
    --处理请求

(1) Connector传来的请求调用CoyoteAdapter.service()方法。(org.apache.catalina.connector.CoyoteAdapter)

Java代码  
  1. public   void  service(org.apache.coyote.Request req,
  2. org.apache.coyote.Response res)
  3. throws  Exception {
  4. ~~略~~
  5. if  (request ==  null ) {
  6. request = (Request) connector.createRequest();
  7. request.setCoyoteRequest(req);
  8. response = (Response) connector.createResponse();
  9. response.setCoyoteResponse(res);
  10. //创建request、response对象

tomcat(一个牛人写的文章,自己看)相关推荐

  1. 下载量高达163万的易语言牛人写的一个超牛的软件(即将删除)

    引自易语言论坛"毁人不倦"贴子(http://bbs.eyuyan.com/dispbbs.asp?boardid=124&id=180180): 在华军上突然发现一个下载 ...

  2. 精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结

    精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结 精华转贴:只是为了记录---我们实验室一个牛人去年写的找工作的总结2008-01-28       15:30最近由于某些原因,不能 ...

  3. 一个牛人给Java初学者的建议(必看篇)

    给初学者之一:浅谈Java及应用学java 从不知java为何物到现在一个小小的j2ee项目经理虽说不上此道高手,大概也算有点斤两了吧每次上网,泡bbs逛论坛,没少去java相关的版 面总体感觉初学者 ...

  4. 一个牛人给java初学者的建议(很有意义,转载的)

    一个牛人给java初学者的建议(很有意义,转载的) 给初学者之一:浅谈java及应用 学java不知不觉也已经三年了 从不知java为何物到现在一个小小的j2ee项目经理 虽说不上此道高手,大概也算有 ...

  5. 牛人写的设计游戏服务器

    转载自 zeeman的博客 - 牛人写的设计游戏服务器 :http://blog.sina.com.cn/s/blog_55d572ca0100uvzt.html 有段时间没有研究技术了,这次正好看到 ...

  6. 俄国牛人写的开源爬虫xNet

    2019独角兽企业重金招聘Python工程师标准>>> 这个一个俄国牛人写的开源工具,为啥说他强悍了,因为他将所有Http协议的底层都实现了一遍,这有啥好处?只要你是写爬虫的,都会遇 ...

  7. 一个日本人写的插件:Breath Controller

    Breath Controller 今天无意发现一个日本人写的 呼吸控制器,挺好玩的,可以从他的 主页 下载源代码. 这个插件目前只支持 人形动画,不过只需要简单的几行修改就可以支持 Generic动 ...

  8. 一个牛人的经历---北京八年——从极度贫困到财务自由(转)

    一个牛人的经历---北京八年--从极度贫困到财务自由 第一章: 八年巨变 我1996年7月从东北的一所曾经非常有名的工科大学毕业,快毕业时听了一位同乡校 友姐姐的话"宁到好地方,不到好单位& ...

  9. 一个印度人写的VC串口类CSerialCom(有串口基础介绍)

    http://www.vc-rs232.com/html/VC_SSCOM_Control/2011/0117/34.html 一个印度人写的VC串口类CSerialCom(有串口基础介绍) 软件介绍 ...

最新文章

  1. 如何在Membership中实现修改密码的功能
  2. 手机web开发的感想
  3. php 实现图片上传并压缩功能
  4. [linux学习] 字符界面linux安装vmtools
  5. TensorFlow基础篇(八)——tf.contrib.layers.l1regularizer()-12_regularizer(lambda)
  6. Salesforce入门教程(中文)-019 VF创建输入表单
  7. 汇总|医学图像分析领域论文
  8. p2p文件服务器,P2P文件传输
  9. PCISPH的通俗解释与简单实现
  10. AppleScript+JavaScript自动认证校园网
  11. Google十大高薪职位:首席软件工程师居首
  12. Flutter学习笔记 数据储存shared_preferences
  13. 创新之道,亚马逊创新之旅背后的故事
  14. 关闭bitLocker驱动器加密
  15. Coursera Algorithm Ⅱ week4 编程作业 Boggle
  16. 美食自媒体好不好做?如何做好美食类账号
  17. p语言是python吗-p语言是python吗
  18. For input String: 异常记录
  19. iphoneXR的tabbar底部图片的适配
  20. MySql-基础查询与排序

热门文章

  1. python矩阵的共轭转置_基础 | Python 下的矩阵操作
  2. 计算机音乐火影吧,【史上最全的火影BGM(背景音乐)】
  3. 轻量化固态激光雷达的三维定位与建图
  4. 名悦集团:暴雨过后车辆如何保养?
  5. eigen 中的matrix
  6. github上值得关注的前端项目
  7. 谷歌刚刚发布了2500万个免费数据集,快来了解一下
  8. Conway(康威)定律
  9. QNX Neutrino 微内核
  10. 手机技巧:手机只剩20%电量?有了这几招,多用2小时