理解与模拟一个简单servlet容器
使用servlet编程需要实现或者继承实现了javax.servlet.Servlet接口的类,其中定义了5个签名方法:
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest req,ServletResponse res) throws ServletException,java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()
init(),service(),destroy对应着servlet的生命周期,init只在加载该servlet时执行且只此一次,容器根据用户请求调用对应servlet的service执行方法,当实例销毁移除前容器调用destroy处理后续操作。
模拟容器主要工作流程:
- 等待http请求
- 根据请求创建对应Request与Response对象
- 如果请求的是静态资源,则调用StaticResourceProcessor发送对应资源
- 如果请求是servlet,则加载该类并执行其service方法
主要类信息如下:
- HttpServer 与web服务器类似,不同的是加入了servlet请求判断,并调用ServletProcessor处理对应servlet
- Request 与上一篇web服务器类似,但是实现了ServletRequest接口
- Response 与上一篇web服务器类似,但是实现了ServletResponse接口
- StaticResourceProcessor 用于处理请求静态资源时调用
- ServletProcessor 用于当请求是servlet时调用
- Constant 定义一些常量
- MyLogger 自己定义在控制台打印日志信息,可以忽略
- PrimitiveServlet 实现servlet接口,自定义servlet程序用于请求调用
说明:部分接口只是实现了需要用到的方法,并没有完全实现所有方法,使用默认即可,代码里面没有贴出来
public class HttpServer {
MyLogger logger = new MyLogger<>(HttpServer.class);
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
private boolean shutdown = false;
public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
logger.log("server started......." + "at " + serverSocket.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
while (!shutdown){
Socket socket = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
socket = serverSocket.accept();
logger.log("accepted new request...");
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
Request request = new Request(inputStream);
request.Parse();
Response response = new Response(outputStream);
response.setRequest(request);
logger.log("inition done,begin process.......");
if(request.getUri() == null){
logger.log("request uri is null...close socket");
socket.close();
continue;
}
else if(request.getUri().startsWith("/servlet/")){
logger.log("execute servlet...");
ServletProcessor servletProcessor = new ServletProcessor();
servletProcessor.process(request, response);
}
else {
logger.log("send staticResource...");
StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();
staticResourceProcessor.process(request, response);
}
socket.close();
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Request implements ServletRequest{
MyLogger logger = new MyLogger(ServletRequest.class);
private String uri;
private InputStream in;
public Request(InputStream in){
this.in = in;
}
public String parseUri(String request){
int index1,index2;
index1 = request.indexOf(" ");
if (index1 != -1){
index2 = request.indexOf(" ", index1+ 1);
if (index1 < index2)
return request.substring(index1 + 1, index2);
}
return null;
}
public void Parse(){
StringBuffer request = new StringBuffer(2048);
byte[] bs = new byte[2048];
int i;
try {
i = in.read(bs);
} catch (IOException e) {
e.printStackTrace();
i = -1;
}
for(int j=0; j<i; j++){
request.append((char)bs[j]);
}
logger.log(request.toString());
uri = parseUri(request.toString());
if(uri != null)
logger.log("uri is " + uri);
}
public String getUri() {
return uri;
}
}
public class Response implements ServletResponse{
MyLogger logger = new MyLogger(Response.class);
private static final int BUFFER_SIZE = 1024;
private Request request;
private OutputStream out;
private PrintWriter writer;
public Response(OutputStream out) {
this.out = out;
}
public void setRequest(Request request) {
this.request = request;
}
//假设请求的是图片资源
public void sendStaticResource() throws IOException{
byte[] buffer = new byte[BUFFER_SIZE];
FileInputStream fis = null;
File file = new File(Constant.WEB_ROOT, request.getUri());
try {
logger.log("Begin read file + " + file.toString());
fis = new FileInputStream(file);
String headerMsg = "HTTP/1.1 200 OK\r\n" +
"Content-Type: image/jpg\r\n" +
"Content-Length: " + file.length() + "\r\n" +
"\r\n" ;
logger.log("headerMsg->\r\n" + headerMsg);
out.write(headerMsg.getBytes());
int ch = fis.read(buffer, 0, BUFFER_SIZE);
while (ch != -1){
out.write(buffer, 0, BUFFER_SIZE);
ch = fis.read(buffer, 0, BUFFER_SIZE);
}
} catch (FileNotFoundException e) {
String html = "<h1>file not found</h1>";
logger.log("FileNotFoundException");
String errorMsg = "HTTP/1.1 404 file not found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: " + html.getBytes().length + "\r\n" +
"\r\n" +
html;
out.write(errorMsg.getBytes());
logger.log("errorMsg->" + errorMsg);
}
finally {
if(fis != null){
fis.close();
}
}
}
}
public class StaticResourceProcessor {
public void process(Request request,Response response) {
try {
response.sendStaticResource();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ServletProcessor {
public void process(Request request,Response response){
String uri = request.getUri();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null;
URL[] urls = new URL[1];
URLStreamHandler urlStreamHandler = null;
File classPath = new File(Constant.WEB_ROOT);
try {
String repository = (new URL("file",null,classPath.getCanonicalPath() +
File.separator)).toString();
urls[0] = new URL(null,repository,urlStreamHandler);
loader = new URLClassLoader(urls);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest)request, (ServletResponse) response);
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class MyLogger<T> {
private String classStr = "";
public void log(T msg){
System.out.println(classStr + "(" +
(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()) + ")" + ": " + msg);
}
public MyLogger(Class classz){
classStr = classz.getName();
}
}
public class PrimitiveServlet implements Servlet{
MyLogger Logger = new MyLogger<>(PrimitiveServlet.class);
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
Logger.log("service execute.....");
PrintWriter writer = response.getWriter();
writer.println("Hey,welcome on board!");
writer.println("lets rock!");
}
}
public class Constant {
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "bin";
}
理解与模拟一个简单servlet容器的更多相关文章
- 一个简单servlet容器
一个简单servlet容器 2.1 javax.servlet.Servlet接口 Servlet编程需要使用javax.servlet和javax.servlet.http两个包下的接口和类 在所有 ...
- 理解与模拟一个简单web服务器
先简单说下几个概念,根据自己的理解,不正确请见谅. web服务器 首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器.最初的web服务器只能用来处理静 ...
- 模拟一个简单的tomcat
目录 简单处理 每个请求一个线程 模拟tomcat 参考 简单处理 // 客户端和服务器的通信,说到底就是两个数据的传输, // 客户端发送inputStream给服务器,服务器回复 // outpu ...
- 自定义模拟一个Spring IOC容器
一.模拟一个IOC容器: 介绍:现在,我们准备使用一个java project来模拟一个spring的IOC容器创建对象的方法,也就是不使用spring的jar自动帮助我们创建对象,而是通过自己手动书 ...
- 【模块化编程】理解requireJS-实现一个简单的模块加载器
在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...
- 使用Socket模拟一个简单的Webservice调用
webservice是对socket的一个封装,让远程调用调用变得更加简单,那么使用socket究竟有多么麻烦呢?来看看. 做一个简单的天气查询: 服务端: public class SocketSe ...
- 模拟一个简单的基于tcp的远程关机程序(转)
最近在学习unix网络编程,现在正在学习tcp的通信.其实,只要建立起了tcp通信,操作远端的计算机就不是什么问题了.正向telnet一样,也是基于tcp/IP协议的.所以这个实验,也算是对telne ...
- java模拟一个简单的QQ
v 项目源码 https://github.com/hjzgg/java_QQ v 标题效果 package testFour; import java.awt.Color; import ...
- spring 理解Spring AOP 一个简单的约定游戏
应该说AOP原理是Spring技术中最难理解的一个部分,而这个约定游戏也许会给你很多的帮助,通过这个约定游戏,就可以理解Spring AOP的含义和实现方法,也能帮助读者更好地运用Spring AOP ...
随机推荐
- myBatis自动生成mapping,dao和model
myBatis没有自动封装实体类.所以都需要自己编写,但是表数据过多时.编写难度就会增加,错误率也会增加! 所以myBatis提供mybatis-generator-core-1.3.2-bundle ...
- 持续获取可访问谷歌的hosts(已证实可用)
@echo off REM 欢迎圈我,在顶栏的"查找人员"处输入Felix Hsu即可 REM Patched by logicmd REM 准备工作,先清一下DNS缓存,再备份h ...
- iOS.ReactNative-4-react-native-command-line-tool
Command line tool: react-native 1. react-native 是一个命令行工具 1.1 react-native简介 运行以下命令: ls -lt `which re ...
- BHP编译器教程
BHP编译器教程 BHP是一个WEB模版编程语言编译器,生成PHP后端代码. 最简单的Helloworld例子 编写一个hello.bhp文件 <? $hello="hello,wor ...
- 尽量少用if else
Michael Feathers是Object Mentor International公司的技术顾问.他的工作不仅是技术开发,他还参与对世界各地技术团队进行培训.指导等工作.他曾开发了将JUnit迁 ...
- Jenkins 笔记
1.Jenkins是什么? 他是一个开源的自动化服务器,持续集成工具.由Java和上百个插件组成,支持编译,测试,部署任意的自动化项目. 2.怎么安装Jenkins? 方法一:从官网 https:// ...
- 抓包工具Charles,anyproxy,mitmproxy等
Charles:图形化界面,看着比较方便友好,也可以抓取https,不过电脑和手机都要下载证书,主要我的电脑上不能添加一添加就卡死 所以,抓取https的话,就用mitmproxy比较简单 1.安装C ...
- NSString 的 compare 方法
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange ...
- HtmlHelper和强类型转换
MVC HtmlHelper;1.Url():<%= Html.ActionLink("用户列表","方法","控制器") %> ...
- Win7 64位 VS2013环境编译CGAL-4.7
看到有人在QQ空间感叹编译CGAL配置折腾了一天时间,自己也想试试,虽然并不打算用,但感觉这库也挺有名的,想必日后用得着,于是着手试着编译. 首先是看一下官网的windows下配置说明 http:// ...