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

[经验分享] tomcat(一个牛人写的文章,自己看)

[复制链接]

尚未签到

发表于 2017-1-30 10:26:10 | 显示全部楼层 |阅读模式

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

  
文章分类:Java编程


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


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

Java代码   DSC0000.png DSC0001.gif






  • 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();   

  •         }   

  •     }    



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代码  






  • 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;   

  •     }   



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代码  






  • 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
    );   


  •         }   

  •     }   



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方法的时序图。

DSC0002.jpg

 

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

(org.apache.catalina.startup.Catalina)。

Java代码  






  • 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"
    );   


  •   

  •     }   



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初始化所完成的工作。

DSC0003.jpg

 


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


★3 容器启动

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


DSC0004.jpg

 


1. Bootstrap调用Catalina的start方法

Catalina.start()方法(org.apache.catalina.startup.Catalina.start())

Java代码  






  • public
     
    void
     start() {   


  •     // 启动server 
      


  •     if
     (server 
    instanceof
     Lifecycle) {   


  •         try
     {   


  •             ((Lifecycle) server).start();   

  •                     ......   

  •    }   



    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代码  






  • public
     
    void
     start() 
    throws
     LifecycleException {         


  •         synchronized
     (services) {   


  •             for
     (
    int
     i = 
    0
    ; i < services.length; i++) {   


  •                 if
     (services 
    instanceof
     Lifecycle)   


  •                     ((Lifecycle) services).start();   

  •             }    

  • }   



public void start() throws LifecycleException {      
synchronized (services) {
for (int i = 0; i < services.length; i++) {
if (services instanceof Lifecycle)
((Lifecycle) services).start();
}  
}
  3. StandardServer调用StandardService的start方法

Java代码  






  • 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 
    instanceof
     Lifecycle)     


  •                    ((Lifecycle) connectors).start();     

  •                   }     

  •        }     

  • }   



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 instanceof Lifecycle)   
((Lifecycle) connectors).start();   
}   
}   
}

  

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


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

  
文章分类:Java编程


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


  ● standardEngine的启动

(1) 首先是StandardEngine.start()被调用

Java代码  






  • public
     
    void
     start() 
    throws
     LifecycleException {   


  •        // Standard container startup   
      


  •       //进行logger,manager,cluster,realm,resource的启动   
      


  •        super
    .start();   


  • }   



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代码  






  • public
     
    synchronized
     
    void
     start() 
    throws
     LifecycleException {   


  • //(省略)  server.xml中配置应用组件的启动    
      


  • //StandardHost容器的启动,   
      


  •         Container children[] = findChildren();     

  •         for
     (
    int
     i = 
    0
    ; i < children.length; i++) {     


  •             if
     (children 
    instanceof
     Lifecycle)     


  •                 ((Lifecycle) children).start();     

  •         }       

  •   

  •     //StandardPipeline的启动(容器与容器间的管道)   
      


  •         if
     (pipeline 
    instanceof
     Lifecycle)     


  •             ((Lifecycle) pipeline).start();    

  • }   



public synchronized void start() throws LifecycleException {
//(省略)  server.xml中配置应用组件的启动   
//StandardHost容器的启动,   
Container children[] = findChildren();   
for (int i = 0; i < children.length; i++) {   
if (children instanceof Lifecycle)   
((Lifecycle) children).start();   
}     
//StandardPipeline的启动(容器与容器间的管道)   
if (pipeline instanceof Lifecycle)   
((Lifecycle) pipeline).start();  
}

  (3) StandardHost.start()被调用 

Java代码  






  • public
     
    synchronized
     
    void
     start() 
    throws
     LifecycleException {   


  • //返回到以上的containerBase#start执行pipeline   
      


  •       super
    .start();    


  • }  



public synchronized void start() throws LifecycleException {
//返回到以上的containerBase#start执行pipeline   
super.start();  
}
  


(4) StandardPipeline#start

Java代码  






  • public
     
    synchronized
     
    void
     start() 
    throws
     LifecycleException {   


  •        // 将会调用HostConfig#start方法   
      


  •        lifecycle.fireLifecycleEvent(START_EVENT, null
    );     


  •     

  •        // Notify our interested LifecycleListeners   
      


  •        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null
    );     


  • }   



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代码  






  • public
     
    void
     start() {    


  •           //部暑webapps   
      


  •           deployApps();              

  •   }   



public void start() {  
//部暑webapps   
deployApps();            
}

  (6) HostConfig#deployApps 

Java代码  






  • 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());               

  • }  



   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代码  






  • protected
     
    void
     deployWARs(File appBase, String[] files) {   


  • ……   

  • deployWAR(contextPath, dir, file);            

  •   }   



protected void deployWARs(File appBase, String[] files) {
……
deployWAR(contextPath, dir, file);         
}

  (8) deployWAR

Java代码  






  • 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);           

  •   }   



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代码  






  • public
     
    void
     start() 
    throws
     LifecycleException {   


  •            // Http11Protocol的启动 
      


  •             protocolHandler.start();   

  • }  



public void start() throws LifecycleException {
// Http11Protocol的启动
protocolHandler.start();
}
  


(2) Http11Protocol#start 

Java代码  






  • public
     
    void
     start() 
    throws
     Exception {   


  • try
     {     


  •             //到了终点的启动   
      


  •             endpoint.start();     

  •         } catch
     (Exception ex) {     


  •             log.error(sm.getString("http11protocol.endpoint.starterror"
    ), ex);     


  •             throw
     ex;     


  •         }  



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代码  






  • 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();     

  •             }     

  •         }  



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代码  






  • 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);     


  •                }     

  • }   



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 的总体结构图:

DSC0005.gif

 

从上图中可以看出 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处理请求的流程大致如下:

DSC0006.jpg

 

Connector组件启动后,会侦听相关的端口的客户端请求。

(1) 接受一个新的连接请求(org.apache.tomcat.util.net.TcpWorkerThread) 

Java代码  






  • 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
    ]);       


  • }  



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代码  






  • 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 的 一个实例 
      


  • }  



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代码  






  • 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 的 一个实例 
      


  • }   



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配置文件。相关类图如下:

DSC0007.jpg

 

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代码  






public
 
void
 service(org.apache.coyote.Request req,      



                    org.apache.coyote.Response res)     


    throws
 Exception {     



         ~~略~~    


   if
 (request == 
null
) {    



        request = (Request) connector.createRequest();   


        request.setCoyoteRequest(req);   


        response = (Response) connector.createResponse();   


     response.setCoyoteResponse(res);   


     //创建request、response对象   
  
</spa

运维网声明 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-335213-1-1.html 上篇帖子: Tomcat 同时侦听多端口,多应用 下篇帖子: Tomcat 服务器的组成部分
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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