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

本文介绍了W3C开发的纯JAVA HTTP服务器Jigsaw的启动过程。从Main类的main函数开始,通过ServerHandlerManager类启动HTTP服务器。解析了server.props配置文件内容,详细讲解了http-server的初始化过程及线程池的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 协议处理请求的过程,有兴趣的朋友可以再仔细去研究一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值