今天我们来一步一步实现从0开始手写Tomcat。 首先,我们要知道Tomcat是什么,能做什么。 Tomcat是一个Web网络应用程序,可以接收请求,并且可以处理请求。接收请求意味着必须要有一个端口,Tomcat默认http端口是8080,请求过来后由socket网络处理,请求最终需要交给线程处理,根据URL调用servlet,之后返回响应内容。 那么要实现Tomcat的功能,首先第一步我们要实现Socket编程。 Socket实际上做了什么呢? Socket调用操作系统的SocketAPI来实现网络处理。所谓网络编程,就是对外开放接口,让我们的程序可以与外部建立连接。 底层Socket API函数定义
了解完socket编程后,我们先来完成Socket网络处理部分,如下: private static ExecutorService threadPool = Executors.newCachedThreadPool(); public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8080); System.out.println('tomcat 服务器启动成功'); while (!serverSocket.isClosed()) { //获取Socket连接 Socket request = serverSocket.accept(); threadPool.execute(() -> { try (InputStream is = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)) ){ System.out.println('收到请求:'); String msg = null; while ((msg = reader.readLine()) != null) { if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println('---------收到请求'); } catch (IOException e) { e.printStackTrace(); } finally { try { if (request != null) { request.close(); } } catch (IOException e) { e.printStackTrace(); } } }); } if (serverSocket != null) { serverSocket.close(); } } 完成Socket网络编程,我们启动服务后,通过telnet可以发现8080端口已启动,但是我们通过浏览器访问http://localhost:8080 却发现浏览器显示“无法访问该页面”。这是为什么呢? 我们的目标是要实现浏览器和Java Web服务器Tomcat实现交互,那么Java Web服务器Tomcat如何与浏览器交互呢? Tomcat和浏览器之间要交互,需要约定一个协议,这样才能正常交互。 Http协议 --- 请求 Http协议 --- 响应 为了实现Java Web服务器Tomca与浏览器之间能正常交互,我们需要加上一段请求响应代码,完整代码如下:
这时候,我们启动服务后,再通过浏览器去访问http://localhost:8080/,我们会发现浏览器返回了“Hello World”。 接下来,我们要实现根据请求URL执行相应的servlet方法。 例如:“GET /servlet-demo-1.0.0/index HTTP/1.1”,我们要根据这样一个请求去找到对应的项目及调用相应的servlet。 首先我们要知道有哪几个项目,请求的项目是哪个,对应的servlet是哪个。通过请求路径,我们可以知道请求的项目名称是“servlet-demo-1.0.0”,请求的servlet路径是 /index 。我们可以根据项目名称查找到对应的项目,读取项目的web.xml,从web.xml中获取到Servlet对应的class,也可以获取到ServletMapping设置的路径来做请求过滤,也可以获取其他信息来做相应的一些操作。 这里有一个问题,获取到的class文件可以执行用来调用Servlet吗? 答案是肯定不行,了解JVM的应该都知道,我们需要先将class文件加载到JVM,然后才能正常调用相应的方法。 项目类资源加载 通过以下代码,我们可以实现对项目类加载,获取到Servlet实例。 //每个项目,类加载器,去加载置顶位置的class信息 URL classUrl = new URL('file:' + projectPath + '\\WEB-INF\\classes\\'); URLClassLoader servletClassLoader = new URLClassLoader(new URL[] {classUrl}); //1、 加载到JVM Class<?> servletClass = servletClassLoader.loadClass(servletClassName); //2、 实例化 Servlet servlet = (Servlet) servletClass.newInstance(); 我们先来回顾一下Servlet的生命周期是怎样的,如下所示: 在我们这个模拟例子中,我们就不实现init()和destory()了,我们就来调用service()方法处理客户端请求。javax.servlet.Servlet的service()方法是有两个参数的
我们在应用开发中常用的HttpServletRequest和HttpServletResponse,实际上是我们的Java Web服务器已经帮我们实现了,这里我们也需要来实现我们的HttpServletRequest和HttpServletResponse,然后在调用service()方法就可以了。到这里,我们简易版的Web服务器就算成功了。 代码地址:https://github.com/biaotang/demo-tomcat |
|