粗汉手撕Tomcat核心原理-BIO版
文章目录
源码地址: https://gitee.com/kylin1991_admin/mini-tomcat/tree/master/bio-tomcat
环境准备
1、maven
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
2、插件:Lombok
相关类图展示
1、配置文件web.properties
servlet.one.url=/firstServlet.do
servlet.one.className=org.example.servlet.FirstServlet
2、顶级抽象类BServlet
public abstract class BServlet {
public void service(BRequest request, BResponse response) throws IOException {
if ("GET".equalsIgnoreCase(request.getMethod())) {
doGet(request, response);
} else {
doPost(request, response);
}
}
protected abstract void doPost(BRequest request, BResponse response)throws IOException;
protected abstract void doGet(BRequest request, BResponse response)throws IOException;
}
3、包装BRequst
@Data
public class BRequest {
private String method;
private String url;
private Map<String, Object> parameters = new HashMap<>();
private InputStream in;
public BRequest(InputStream in) {
this.in = in;
init();
}
// 包装用户请求为java参数
private void init() {
String content = "";
byte[] buff = new byte[1024];
int len = 0;
try {
if ((len = in.read(buff)) != -1) {
content = new String(buff);
}
if (!"".equals(content)) {
String[] requestHead = content.split(" ");
this.setMethod(requestHead[0]);
String[] requestUrl = requestHead[1].split("\\?");
this.setUrl(requestUrl[0]);
if (requestUrl.length > 1) {
String[] requestParameters = requestUrl[1].split("&");
for (String requestParameter : requestParameters) {
String[] inx = requestParameter.split("=");
parameters.put(inx[0], inx[1]);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、包装BResponse
public class BResponse {
private OutputStream out;
public BResponse(OutputStream out) {
this.out = out;
}
// 响应请求
public void write(String context) throws IOException {
String stringBuffer = "HTTP/1.1 200 OK\n" +
"Content-Type: text/html\n" +
"\r\n" +
context;
out.write(stringBuffer.getBytes());
}
}
5、BTomcat启动类
public class BTomcat {
private static final int PORT = 8080;
private static Map<String, BServlet> servletMapping = new HashMap<>();
private static String WEB_URL = "web.properties";
// 初始化配置和映射关系
public void init() {
try {
FileInputStream fileInputStream = new FileInputStream(this.getClass().getResource("/").getPath() + WEB_URL);
Properties properties = new Properties();
properties.load(fileInputStream);
for (Object k : properties.keySet()) {
String key = k.toString();
if (key.endsWith(".url")) {
// 取出url前面的前缀 servlet.one.
String prefixKey = key.replaceAll("\\.url$", "");
String url = properties.getProperty(key);
String className = properties.getProperty(prefixKey + ".className");
BServlet obj = (BServlet) Class.forName(className).newInstance();
servletMapping.put(url, obj);
}
}
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
// 启动服务
public void start() {
init();
try {
ServerSocket server = new ServerSocket(this.PORT);
System.out.println("B Tomcat 已启动,监听的端口是:" + this.PORT);
while (true) {
Socket client = server.accept();
process(client);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void process(Socket client) throws IOException {
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
BRequest request = new BRequest(in);
BResponse response = new BResponse(out);
String url = request.getUrl();
if (servletMapping.containsKey(url)) {
servletMapping.get(url).service(request, response);
} else {
response.write("404 - Not Found");
}
out.flush();
out.close();
in.close();
client.close();
}
public static void main(String[] args) {
new BTomcat().start();
}
6、测试服务类
public class FirstServlet extends BServlet {
@Override
public void doGet(BRequest request, BResponse response) throws IOException {
this.doPost(request, response);
}
@Override
public void doPost(BRequest request, BResponse response) throws IOException {
response.write("This is First Servlet");
}
}
好了。至此。直接启动BTomcat 就可以访问了。