我曾经利用Servlet,JSP,JAX-RS,Spring框架,Play框架,带有Facelets的JSF和一些Spark框架。 以我的拙见,所有这些解决方案都远非面向对象和优雅的。 它们都充满了静态方法,无法测试的数据结构和肮脏的骇客。 因此,大约一个月前,我决定创建自己的Java Web框架。 我将一些基本原则纳入其基础:1)没有NULL,2)没有公共静态方法,3)没有可变的类以及4)没有类的转换,反射和instanceof
运算符。 这四个基本原则应保证干净的代码和透明的体系结构。 这就是Takes框架的诞生方式。 让我们看看创建了什么以及它如何工作。
简而言之,Java Web体系结构
简单来说,这就是我理解Web应用程序体系结构及其组件的方式。
首先,要创建Web服务器,我们应该创建一个新的网络套接字 ,该套接字在某个TCP端口上接受连接。 通常是80,但是我将使用8080进行测试。 这是通过Java使用ServerSocket
类完成的:
import java.net.ServerSocket;
public class Foo {
public static void main(final String... args) throws Exception {
final ServerSocket server = new ServerSocket(8080);
while (true);
}
}
这足以启动Web服务器。 现在,套接字已准备就绪并且正在侦听端口8080。当有人在其浏览器中打开http://localhost:8080
时,将建立连接,浏览器将永远旋转其等待轮。 编译此代码段,然后尝试。 我们只是构建了一个简单的Web服务器,而没有使用任何框架。 我们尚未对传入的连接做任何事情,但是我们也不拒绝它们。 所有这些都在该server
对象内对齐。 它是在后台线程中完成的。 这就是为什么我们需要将while(true)
放在后面。 没有这种无休止的暂停,该应用程序将立即完成其执行,并且服务器套接字将关闭。
下一步是接受传入的连接。 在Java中,这是通过对accept()
方法的阻塞调用来完成的:
final Socket socket = server.accept();
该方法正在阻塞其线程,并等待新的连接到达。 一旦发生这种情况,它将返回Socket
的实例。 为了接受下一个连接,我们应该再次调用accept()
。 因此,基本上,我们的Web服务器应该像这样工作:
public class Foo {
public static void main(final String... args) throws Exception {
final ServerSocket server = new ServerSocket(8080);
while (true) {
final Socket socket = server.accept();
// 1. Read HTTP request from the socket
// 2. Prepare an HTTP response
// 3. Send HTTP response to the socket
// 4. Close the socket
}
}
}
这是一个无休止的循环,接受一个新的连接,理解它,创建一个响应,返回响应,然后再次接受一个新的连接。 HTTP协议是无状态的,这意味着服务器不应记住任何先前连接中发生的情况。 它关心的只是此特定连接中的传入HTTP请求。
HTTP请求来自套接字的输入流,看起来像是多行文本块。 如果读取套接字的输入流,将看到以下内容:
final BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
while (true) {
final String line = reader.readLine();
if (line.isEmpty()) {
break;
}
System.out.println(line);
}
您将看到如下内容:
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6,uk;q=0.4
客户端(例如Google Chrome浏览器)将此文本传递到已建立的连接中。 它连接到localhost
端口8080,一旦连接就绪,它将立即将文本发送到其中,然后等待响应。
我们的工作是使用在请求中获得的信息来创建HTTP响应。 如果我们的服务器非常原始,那么我们基本上可以忽略请求中的所有信息,而只需返回“ Hello,world!”。 到所有请求(为简单起见,我使用IOUtils
):
import java.net.Socket;
import java.net.ServerSocket;
import org.apache.commons