一、Servlet接口体系实现
1. Servlet接口定义
public interface Servlet {
public void init(); // 容器初始化时调用(生命周期起点)
public void service( // 处理请求的核心入口
HttpServletRequest request,
HttpServletResponse response
);
public void destroy(); // 容器关闭时调用(资源回收)
}
2. 通用抽象类实现
public abstract class GenericServlet implements Servlet {
public void init() {
System.out.println("初始化servlet"); // 默认初始化逻辑(可被子类覆盖)
}
public void destroy() {
System.out.println("销毁servlet"); // 默认销毁逻辑(可被子类覆盖)
}
}
3. HTTP协议专属实现
public abstract class HttpServlet extends GenericServlet {
@Override
public void service(HttpServletRequest request, HttpServletResponse response) {
// 根据请求方法动态分发逻辑
if (request.getMethod().equals("GET")) {
doGet(request, response); // 触发GET请求处理
}
else if (request.getMethod().equals("POST")) {
doPost(request, response); // 触发POST请求处理
}
}
// 子类必须实现的抽象方法(框架级约束)
protected abstract void doGet(HttpServletRequest request, HttpServletResponse response);
protected abstract void doPost(HttpServletRequest request, HttpServletResponse response);
}
二、容器启动类(MyTomcat.java)
1. 主入口与初始化
public class MyTomcat {
static HttpServletRequest request = new HttpServletRequest();
public static void main(String[] args) throws IOException {
ServletConfigMapping.init(); // 加载所有@WebServlet注解类
ServerSocket serverSocket = new ServerSocket(8080); // 绑定8080端口
while(true){ // 永久监听循环
Socket socket = serverSocket.accept(); // 阻塞等待客户端连接
InputStream inputStream = socket.getInputStream();
// 读取请求原始字节流
int count = 0;
while (count == 0){
count = inputStream.available(); // 获取可读字节数(非阻塞检查)
}
byte[] bytes = new byte[count];
inputStream.read(bytes); // 读取完整请求数据
String Context = new String(bytes);
System.out.println("原始请求数据:\n" + Context);
2. 请求解析与路由
if(!Context.isEmpty()){
// 解析HTTP协议首行(示例:GET /index HTTP/1.1)
String firstLine = Context.split("\\n")[0]; // 按换行符切割取首行
String[] parts = firstLine.split("\\s"); // 按空格切割
// 封装请求对象
request.setMethod(parts[0]); // 第一个元素为方法类型
request.setPath(parts[1]); // 第二个元素为请求路径
System.out.println("解析结果: " + request.getMethod() + " " + request.getPath());
}
// 路由查找逻辑
if(servletContext.containsKey(request.getPath())){
HttpServlet servlet = servletContext.get(request.getPath());
// 输出 Servlet 对象的映射信息
System.out.println( request.getPath() + ": " + servlet);
System.out.println("路由成功 -> " + servlet.getClass().getName());
servlet.service(request, new HttpServletResponse()); // 调用Servlet入口
}else{
System.out.println("没有找到对应的Servlet");
}
}
}
}
三、Servlet注册管理(ServletConfigMapping.java)
1. 注解扫描与实例化
public class ServletConfigMapping {
//1、扫描com.qcby.webapps下面的所有文件,并获取全路径名
//2、根据全路径名获取类对象,在获取类对象上的@WebServlet注解
//3、创建servlet对象,并注册到servletContext中
// servlet 容器
public static Map servletContext = new HashMap<>();
public static void init() {
List classesPath = SearchClassUtil.searchClass();
for (String s: classesPath) {
try {
getWebServletAnnotation(s);
} catch (Exception e) {
e.printStackTrace();
}
}
//System.out.println("Servlet registered with path: " + path);
}
// 获取类上的@WebServlet注解
private static void getWebServletAnnotation(String className) throws Exception {
// 使用全类名加载类
Class> clazz = Class.forName(className);
// 获取类上的@WebServlet注解
WebServlet webServlet = clazz.getAnnotation(WebServlet.class);
// 注册servlet
servletContext.put(webServlet.urlMapping(), (HttpServlet) clazz.newInstance());
}
}
2. 自定义注解定义
@Retention(RetentionPolicy.RUNTIME) //表明注解仅用于源代码级别
@Target(ElementType.TYPE) //表明注解可以用于类上
public @interface WebServlet {
String urlMapping() default "/"; //urlPatterns属性,默认值是"/"
}
四、请求/响应对象实现
1. 请求对象封装
public class HttpServletRequest {
private String path; // 请求路径(如"/login")
private String method; // HTTP方法(GET/POST)
// 工具方法:通过setter注入数据
public void setPath(String path) { this.path = path; }
public void setMethod(String method) { this.method = method; }
// 供Servlet获取请求信息
public String getPath() { return path; }
public String getMethod() { return method; }
}
2. 响应对象骨架
public class HttpServletResponse {
// 预留扩展点(后续可添加状态码、响应头等功能)
}
五、工作流程示例
1. 定义业务Servlet
@WebServlet(urlMapping = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("处理/api的GET请求");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
System.out.println("处理/api的POST请求");
}
}
2. 控制台输出示例
GET /login HTTP/1.1
/login: com.qcby.webapps.myweb.LoginServlet@610455d6
路由成功 -> com.qcby.webapps.myweb.LoginServlet
处理/login的GET请求