不知道大家做项目时有没有这种感觉,尤其是刚开始学Java一年的时候有点摸不着头脑,只知道按照网上的代码走,自己以前也是这样的,感觉Java这个东西吧,看看别人写好的源码就OK了,Copy过来实现效果就好了。其实并不是这样的。废话不多说,今天我们就来徒手写一个tomcat Web容器,阐明Jboss为什么在企业级开发场景应用的多和它的主流性。
我们先来新建一个Java project项目,新建一个用来处理用户的单个请求的子线程处理类Handler,
package com.tz.tomcat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
/**
* 用来处理用户的单个请求的子线程处理类
* @author ZJ
*
*/
public class Handler implements Runnable{
private Socket socket;
public Handler(Socket socket){
this.socket = socket;
}
/**
* 执行子线程响应处理
*/
@Override
public void run() {
try {
//解析请求,获取
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String tmp = "";
while ((tmp=br.readLine())!=null && tmp.length()>0) {
sb.append(tmp);
sb.append("\r\n");
}
System.out.println(sb.toString());
//相当于Web项目的WebRoot文件夹 我们在F盘下新建一个web文件夹,在里面放入360搜索的官网
String WebRoot = "f:/web";
String[] msgs = sb.toString().split(" ");
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os));
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type:text/html;charset=utf-8");
pw.println();
pw.flush();
if(msgs.length>2){
FileInputStream fileIs = new FileInputStream(new File(WebRoot+msgs[1]));
byte[] buf = new byte[1024];
int len = 0;
while ((len=fileIs.read(buf))!=-1) {
os.write(buf, 0, len);
}
fileIs.close();
os.close();
}
pw.close();
System.out.println("你好,欢迎来到这里");
} catch (Exception e) {
}
}
}
再新建一个Server类
package com.tz.tomcat;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* tomcat Web应用程序的主入口
* @author ZJ
*
*/
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(80);//浏览器默认的访问端口
while(true){
//阻塞方法,没有请求连接时,程序会在这里等待
Socket socket = ss.accept();
Thread tr = new Thread(new Handler(socket));
tr.start();
}
} catch (IOException e) {
}
}
}
运行Server类,在浏览器中输入localhost/index.css 或localhost/1.html 再想想我们新建一个web项目时下面的WebRoot文件夹,似乎也是同样的道理。
除了图片打开乱码外,其他的文件大部分都能通过localhost/...打开(你们可以自己试试能不能打开游戏,视频啥的)这里大家自由发挥,虽然说图片不能直接获取到,但是看看下面的代码就知道我们为什么用上面这种方式了。
package com.tz.tomcat;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
* @author ZJ
*
*/
public class TestTomcat {
public static void main(String[] args) throws IOException {
//浏览器相当于一个客户端
ServerSocket server = new ServerSocket(80);
System.out.println("开始等待连接");
//等待浏览器返回
Socket socket = server.accept();
System.out.println("请求成功");
//解析请求 获取
InputStream is = socket.getInputStream();
//将字符串转换为字节流再包装字符缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String tmp = "";
while ((tmp=br.readLine())!=null && tmp.length()>0) {
sb.append(tmp);
sb.append("\r\n");
}
System.out.println(sb.toString());
//tomcat容器将根目录下的文件解析 响应给浏览器
String WebRoot = "f:/web";
String[] msgs = sb.toString().split(" ");
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os));
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type:text/html;charset=utf-8");
pw.println();
pw.flush();
if(msgs.length>2){
FileInputStream fileIs = new FileInputStream(new File(WebRoot+msgs[1]));
byte[] buf = new byte[1024];
int len = 0;
while ((len=fileIs.read(buf))!=-1) {
os.write(buf, 0, len);
}
fileIs.close();
os.close();
}
pw.close();
System.out.println("响应完成");
}
}
执行这段代码你会发现图片,js,css都不能正常的加载出来,而且还是单线程的。
对比上面的两个小例子,我相信你肯定会有所理解tomcat的实现原理。但是实际上再企业级项目实战中,为什么我们一般不用tomcat容器呢,而用Jboss,WebSphere,WebLogic容器呢。目前我所在的公司就是用的Jboss。
在以后的章节我会详细的说明Jboss优于tomcat的方面。敬请期待!