声明:该文章为转载的一个泡友的原创,泡友...泡友...泡友........你在那里呀 ??
1. tomcat 的基本原理
tomcat按以下的步骤对外提供服务
- 定义web.xml文件
- 读取web.xml文件,将配置信息读取到某个地方
- 定义ServerSocket,持续监听服务
- 服务到来后处理请求
- 请求处理完成后返回结果
2. 手写Demo
2.1 代码结构
2.2 定义web.xml 文件
为简单起见,使用web.properties定义,代码如下:
servlet.one.url=/login
servlet.one.classname=com.northleaf.servlet.LoginServlet
2.3 定义Request ,用于封装传递进来的请求
此类中同时封装了其它的几个字段:method,url
public class Request {
private String method;
private String url;
// 此处省略get方法
public Request(InputStream inputStream) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//将读取到的第一行显按空格拆分出方法与url
String[] methodAndUrl = bufferedReader.readLine().split(" ");
this.method= methodAndUrl[0];
this.url=methodAndUrl[1];
}
}
2.4 定义Response,用于封装返回给客户端的请求
在此代码中,定义一个http协议头,有些浏览器,比如chrome,无法识别不带协议头的的报文
public class Response {
public OutputStream outputStream;
public static final String responseHeader="HTTP/1.1 200 \r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n";
public Response(OutputStream outputStream) throws IOException {
this.outputStream= outputStream;
}
}
2.5 定义Servlet 父类
此类中模仿httpservlet类,添加service,doget、dopost方法
public abstract class Servlet {
public void service(Request request, Response response) {
//判断是调用doget 还是 dopost
if ("get".equalsIgnoreCase(request.getMethod())) {
this.doGet(request, response);
} else {
this.doPost(request, response);
}
}
public abstract void doGet(Request request, Response response);
public abstract void doPost(Request request, Response response);
}
2.6 定义一个具体的Servlet类,继承其父类
public class LoginServlet extends Servlet {
@Override
public void doGet(Request request, Response response) {
this.doPost(request,response);
}
@Override
public void doPost(Request request, Response response) {
try {
OutputStream outputStream = response.outputStream;
String res = Response.responseHeader+"Hello,welcome to here !";
outputStream.write(res.getBytes());
outputStream.flush();
outputStream.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
2.7 定义SocketProcess类
此类为一个线程,用于处理接收到的客户端Socket
public class SocketProcess extends Thread{
protected Socket socket;
public SocketProcess(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
Request request = new Request(socket.getInputStream());
Response response = new Response(socket.getOutputStream());
Servlet servlet = MyTomcat.servletMapping.get(request.getUrl());
if (servlet != null) {
servlet.service(request,response);
}else{
String res = Response.responseHeader+"Hello World";
OutputStream outputStream = socket.getOutputStream();
outputStream.write(res.getBytes());
outputStream.flush();
outputStream.close();
}
}catch (Exception ex){
ex.printStackTrace();
}finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
注:如果在web.properties文件中没有找到客户端请求的url,则直接返回“Hello World”
2.8 定义tomcat类
此类为核心类,分几步走:
第一步: 定义变量,用于存储相关的内容
private static final int port = 8099;
private static final Properties properties = new Properties();
public static final HashMap<String, Servlet> servletMapping = new HashMap<>();
第一步: 定义init方法,读取配置文件
此方法重点是将web.properties中的内容读到取ServletMapping中
private void init() {
InputStream io = null;
String basePath;
try {
//获取basePath
basePath = MyTomcat.class.getResource("/").getPath();
System.out.println(basePath);
io = new FileInputStream(basePath + "web.properties");
properties.load(io);
io.close();
//初始化ServletMapping
//返回属性key的集合
Set<Object> keys = properties.keySet();
for (Object key : keys) {
if (key.toString().contains("url")) {
System.out.println(key.toString() + "=" + properties.get(key));
//根据key值获取className
Object classname = properties.get(key.toString().replace("url", "classname"));
servletMapping.put(properties.get(key.toString()).toString(),
(Servlet) Class.forName(classname.toString()).newInstance());
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (io != null) {
try {
io.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
第三步:启动服务,并监听
private void start() {
try {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Tomcat 服务已启动,地址:localhost ,端口:" + port);
//持续监听
do {
Socket socket = serverSocket.accept();
System.out.println(socket);
//处理任务
Thread thread = new SocketProcess(socket);
thread.start();
} while (true);
} catch (IOException e) {
e.printStackTrace();
}
}
注: 此文档为咕泡公开课的笔记整理