理解与模拟一个简单servlet容器

时间:2023-03-08 16:58:17
理解与模拟一个简单servlet容器
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方法
简单servlet容器

主要类信息如下:

  1. HttpServer  与web服务器类似,不同的是加入了servlet请求判断,并调用ServletProcessor处理对应servlet
  2. Request   与上一篇web服务器类似,但是实现了ServletRequest接口
  3. Response   与上一篇web服务器类似,但是实现了ServletResponse接口
  4. StaticResourceProcessor  用于处理请求静态资源时调用
  5. ServletProcessor 用于当请求是servlet时调用
  6. Constant 定义一些常量
  7. MyLogger 自己定义在控制台打印日志信息,可以忽略
  8. PrimitiveServlet 实现servlet接口,自定义servlet程序用于请求调用

说明:部分接口只是实现了需要用到的方法,并没有完全实现所有方法,使用默认即可,代码里面没有贴出来

(一)HttpServer 
 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();
}
}
}
}
(二)Request 
 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;
}
}
(三)Response 
 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();
}
}
}
}
(四)StaticResourceProcessor 
 public class StaticResourceProcessor {
public void process(Request request,Response response) {
try {
response.sendStaticResource();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(五)ServletProcessor 
 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();
} }
}
(六)MyLogger 
 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();
}
}
(七)PrimitiveServlet 
 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!");
} }
(八)Constant 
public class Constant {
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "bin";
}