W3C的HTTP服务器jigsaw的启动过程

HTTP 服务器 jigsaw 的启动过程

Jigsaw W3C 开发的纯 JAVA HTTP 服务器,研究它的开源代码可以了解到不少优秀的设计理念,现在讲讲它的启动过程

整个程序是从 org.w3c.jigsaw.Main 这个类启动的,它提供了一个简单的 main 函数,用以调用 org.w3c.jigsaw.daemon.ServerHandlerManager main 函数, ServerHandlerManager 是个很重要的类,它持有服务器的句柄,在它的 main 方法中最后一行,创建了 ServerHandlerManager 的一个实例,从而开始了服务器的实质启动过程。

ServerHandlerManager (String args[], File config, Properties props)

这是创建 ServerHandlerManager 实例的构造方法原型,参数 args 是控制台参数, config 是配置文件 server.props 的系统路径, props 用以保存服务器的系统参数。配置文件 server.props 中的内容已经在 main 方法中被读取并保存在参数 props 中, server.props 的内容如下:

org.w3c.jigsaw.daemon.handlers=http-server|admin-server

http-server.org.w3c.jigsaw.daemon.class= org.w3c.jigsaw.http.httpd

admin-server.org.w3c.jigsaw.daemon.class=org.w3c.jigsaw.admin.AdminServer

(注:第一行 http-server admin-server 是启动并创建的服务器的 id ,它们分别对应于后两行的两个类: httpd AdminServer admin-server 是用于管理 jigsaw 的服务器,我这里只研究了提供 http 服务的 http-server 服务器,管理服务器的设计应该是差不多的,有兴趣的可以去看看它的源代码,以下内容都是对 http-server 的学习)

1 launchServerHandler(String id, DaemonProperties props)

构造函数调用了该方法,在这个方法中加载了 http-server.props 配置文件,并初始化了 http-server 服务器, http-server 的句柄也被保存在 ServerHandlerManager 中。下面看一看 http-server 也就是 httpd 的初始化方法 initialize() ,里面主要调用了两个方法, initializeProperties() 初始化了 httpd 的服务器参数,而 initializeServerSocket() 做了非常重要的工作 :

a 、首先创建了客户对象工厂类 SocketClientFactory 的实例,并初始化了该实例的各个参数。在这些参数中有两个参数需要特别关注,一个是 freeList ,它是一个链表,保存了新创建的所有代表 http 请求的客户对象(实际上这个链表每个节点是一个客户对象的状态 SocketClientState ,每个 SocketClientState 对象都和真正的客户 SocketClient 对象绑定);另一个是 threadcache ,它是一个线程缓存池,服务器启动过程中创建的线程都加入到该池中,它们都作为守护线程启动,第一次运行都是阻塞的,后面有 http 请求服务时才会唤醒并用来处理客户对象的请求。

b 、调用工厂类的创建服务器套接字方法初始化了 httpd 的参数 serversocket ,对指定端口进行监听

c httpd 有一个 thread 属性,它用当前的 httpd 对象创建了 Thread 实例并赋给了这个属性, this.thread   = new Thread (this)

这是一个我感到设计很精妙的地方, httpd 是一个实现了 Runnable 接口的类,在后面的方法中将会看到对 thread start() 方法的调用,实际上就是启动了 httpd 服务器线程

2 、调用 httpd start() 方法。

这里面除了其他初始化方法外,就是调用了上面所说的 thread 属性的 start() 方法,从而运行 httpd run() 方法, http 服务器启动过程到此就完成了。

当有一个新连接请求时,在 run() 方法中, serversocket.accept() 返回一个客户套接字,并作为参数传给客户工厂类的 handleConnection() 方法,在这个方法中首先从 freeList 链表中获取一个 SocketClientState 对象,并将客户套接字绑定到对应的 SocketClient 对象上:

SocketClientState cs = null;

cs = (SocketClientState) freeList.removeTail();

cs.client.bind(socket);

bind() 方法中,调用了工厂类 SocketClientFactory run() 方法,请看代码:

protected void run(SocketClient client) {

       if ( debug )

           System. out .println(client+ ": warming up..." );

       // 从线程池 threadcache 取得一个线程用以运行 client run() 方法

       boolean threaded = threadcache .getThread(client, true );

      

       if ( debug )

           System. out .println(client+ ": threaded=" +threaded);

    }

客户对象 SocketClient 作为参数传给了线程池 threadcache getThread() 方法,从线程池中获取一个线程来处理这个连接,成功获取一个空闲线程后,便可以唤醒该线程。这里有必要说一下,线程池中启动的守护线程都是 CachedThread 实例,它继承了 Thread 类, CachedThread 有一个 Runnable 属性 runner ,而客户对象 SocketClient 实现了 Runnable 接口,从池中取得一个守护线程后,传过来的客户对象 SocketClient 参数会赋给 runner 属性,被唤醒的守护线程便调用 runner 也就是 SocketClient 对象的 run() 方法,开始处理 http 请求,之后就是使用 http 协议处理请求的过程,有兴趣的朋友可以再仔细去研究一下。

你可能感兴趣的:(thread,c,properties,HTTP服务器,服务器,behavior)