`
0428loveyu
  • 浏览: 30564 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

实现一个简单的Servlet容器

 
阅读更多

Servlet规范定义了一个API标准,这一标准的实现通常称为Servlet容器,比如开源的Tomcat、JBoss。容器提供一些基本的服务,使得开发者专注于业务领域。当一个请求到达时,监听在相应端口的容器会接受该请求,将请求的信息转化成一个ServletRequest对象,同时创建一个ServletResponse对象,我们在开发Servlet应用时,就可以直接使用这两个对象(容器传递到service()方法的参数)。因此,所谓容器(服务器、中间件等),就是提供一些底层的、业务无关的基本功能,为真正的Servlet提供服务。

例如,在Http请求到达的时候,请求是一个标准的Http请求,包括请求方法、URI、协议、客户端环境参数、请求参数等等。容器通过Socket接收这些信息,并将其转化成特定于Servlet的ServletRequest对象。我们无需关注底层的网络Socket细节就可以直接使用。同样,容器也创建好一个ServletResponse,它帮我们设置了一些返回操作的基本内容,比如用于写入的OutputStream,容器已经把这个输出流定向到客户端的机器上,因此我们操作ServletResponse对象时,是在容器提供的服务至上的。

容器还负责根据请求的信息找到对应的Servlet,传递Request和Response参数,调用Servlet的service方法,完成请求的响应。


接下来我们事先一个简单的、最基本的容器:

时序图如下:



下面给出源码:

SimpleContainer:

package simpleserver.simplecontainer;

import static simpleserver.simplecontainer.Constant.HOSTNAME;
import static simpleserver.simplecontainer.Constant.LOG_BAKC;
import static simpleserver.simplecontainer.Constant.PORT;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SimpleContainer {

	private boolean shutdown = false;
	private Log log = LogFactory.getLog(this.getClass());

	public static void main(String[] args) {
		SimpleContainer server = new SimpleContainer();

		server.start();

	}

	private void start() {
		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket(PORT, LOG_BAKC,
					InetAddress.getByName(HOSTNAME));
		} catch (IOException e) {
			System.out.println("Server starts failed");
			e.printStackTrace();
			System.exit(1);
		}
		log.info("Server starts successfully.");
		service(serverSocket);

	}

	private void service(ServerSocket serverSocket) {
		while (!shutdown) {
			try {
				processRequest(serverSocket);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	private void processRequest(ServerSocket serverSocket) throws IOException {

		log.info("waitting for incoming request ... ");
		Socket socket = serverSocket.accept();
		log.info("receive a request from "
				+ socket.getRemoteSocketAddress().toString());
		InputStream in = socket.getInputStream();
		BaseRequest request = new BaseRequest(in);
		log.info("Request Object ready!");

		OutputStream out = socket.getOutputStream();
		BaseResponse response = new BaseResponse(out);
		ServletProcessor.processServletRequest(request, response);

		socket.close();

	}
}

BaseRequest:只给出部分实现,其他都是ServletRequest的空实现


package simpleserver.simplecontainer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;

import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class BaseRequest implements ServletRequest {

	private InputStream inputStream;
	private String uri;
	private StringBuffer requestContentBuffer = new StringBuffer(2048);

	public BaseRequest(InputStream in) {
		this.inputStream = in;
		prepareContent();
		parseAndSetUri();
	}

	

	private void prepareContent() {

		byte[] buffer = new byte[2048];
		int i = -1;

		try {
			i = inputStream.read(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		for (int k = 0; k < i; k++) {
			requestContentBuffer.append((char) buffer[k]);
		}
		System.out.println(requestContentBuffer.toString());

	}

	private void parseAndSetUri() {
		String requestString = requestContentBuffer.toString();
		int index1 = requestString.indexOf(' ');
		int index2 = -1;
		if (index1 != -1) {
			index2 = requestString.indexOf(' ', index1 + 1);
		}
		this.uri = (index2 > index1) ? requestString.substring(index1 + 1,
				index2) : null;

	}

	public String getUri() {
		return this.uri;
	}

     ......
}

BaseResponse:

public class BaseResponse implements ServletResponse {

	private OutputStream outputStream;

	public BaseResponse(OutputStream out) {
		this.outputStream = out;
	}
    ......
}

ServletProcessor:

package simpleserver.simplecontainer;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ServletProcessor {

	private static Log log = LogFactory.getLog(ServletProcessor.class);

	public static void processServletRequest(BaseRequest request,
			BaseResponse response) {
		String uri = request.getUri();
		String servletName = MappingHelper.resolve(uri);
		log.info("Processing servlet: " + servletName);

		Servlet servlet = loadServlet(servletName);

		callService(servlet, request, response);

	}

	private static URLClassLoader createUrlClassLoader() {

		URLClassLoader loader = null;
		try {
			URL[] urls = new URL[1];
			URLStreamHandler streamHandler = null;
			File classPath = new File(Constant.RESOURCE_ROOT);

			// org.apache.catalina.startup.ClassLoaderFactory
			String repository = (new URL("file", null,
					classPath.getCanonicalPath() + File.separator)).toString();
			urls[0] = new URL(null, repository, streamHandler);
			loader = new URLClassLoader(urls);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return loader;
	}

	private static Servlet loadServlet(String servletName) {
		URLClassLoader loader = createUrlClassLoader();
		Servlet servlet = null;
		try {
			@SuppressWarnings("unchecked")
			Class<Servlet> servletClass = (Class<Servlet>) loader
					.loadClass(servletName);
			servlet = (Servlet) servletClass.newInstance();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return servlet;
	}

	private static void callService(Servlet servlet, ServletRequest request,
			ServletResponse response) {
		try {
			servlet.service(request, response);
		} catch (ServletException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

MappingHeler:
package simpleserver.simplecontainer;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class MappingHelper {

	public static Properties requestMapping;
	static {
		requestMapping = new Properties();
		try {
			requestMapping.load(new FileInputStream(Constant.MAPPING_FILE));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static String resolve(String requestPath) {
		return requestMapping.getProperty(requestPath);
	}

}

该类负责请求URL到Servlet的映射,读入一个属性文件,如下:

/servlet/PrimitiveServlet=simpleserver.simplecontainer.webapp.PrimitiveServlet
/servlet/Test=simpleserver.simplecontainer.webapp.TestServlet

另外还有一个帮助类定义常量。


欢迎交流。


分享到:
评论

相关推荐

    一个简单的servlet容器

    本主题将深入探讨“一个简单的Servlet容器”的实现,参考自《深入剖析Tomcat》这本书的第二章。 Servlet容器的主要职责是接收HTTP请求,然后调用相应的Servlet来处理这些请求,并将Servlet的响应返回给客户端。在...

    简单的servlet容器实现

    这里,我们创建了一个简单的HTML响应,并将其写入到输出流中。实际的Servlet容器会根据请求的URL和方法调用相应的Servlet实例,并让Servlet生成响应内容。 此外,我们注意到有一个`SHUTDOWN_COMMAND`常量,这可能是...

    servlet基础与servlet容器模型

    Servlet容器模型的另一个关键特性是多线程模型。由于HTTP请求是无状态的,Servlet容器通常为每个请求创建一个新的线程来调用Servlet的`service()`方法,以提高并发性能。这意味着Servlet必须是线程安全的,避免在多...

    servlet容器工作原理

    文章中提到的`PrimitiveServlet`是一个简单的Servlet示例,它实现了`javax.servlet.Servlet`接口。具体来看: 1. **`init(ServletConfig config)`**:此方法在Servlet首次初始化时被调用,用于完成初始化操作。 2. ...

    SpringBoot之配置嵌入式Servlet容器.pdf

    2. 编写一个实现了EmbeddedServletContainerCustomizer接口的Bean,通过编程方式设置Servlet容器的配置项,如端口号、上下文路径及会话超时时间。 注册Servlet三大组件(Servlet、Filter和Listener)是构建Web应用...

    一个支持servlet的web服务器.rar

    3. **Resin**:由Caucho公司开发,也是一个强大的Servlet容器,特别适合处理高并发请求。Resin的部署方式也包括将Web应用的目录结构放入其指定的webapps目录。 在Servlet容器中,Servlet生命周期包括加载、初始化、...

    Servlet 容器工作原理解析

    首先,Servlet容器,如Tomcat,是一个独立的产品,它遵循Java EE(J2EE)规范中的Servlet API,为Servlet提供了一个标准化的执行环境。Servlet与Servlet容器的关系类似于枪和子弹,Servlet容器为Servlet提供了运行...

    Servlet容器工作原理讲解

    下面是一个简单的Servlet示例,即`PrimitiveServlet`,它实现了Servlet接口并打印出调用的方法名: ```java public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ...

    基于Java web服务器简单实现一个Servlet容器

    在上述Java web服务器的基础上实现Servlet容器,主要是扩展了对Servlet请求的处理能力。Servlet容器是Java Web应用的核心组件,它负责管理和调用Servlet实例,处理HTTP请求并生成响应。这里我们先了解Servlet的基本...

    Servlet实现简单购物车

    在本项目中,"Servlet实现简单购物车"是指利用Servlet技术来构建一个基础的在线购物车系统。这个系统可能包括添加商品到购物车、查看购物车内容、修改商品数量以及清空购物车等功能。 首先,我们需要了解Servlet的...

    利用servlet监听器,系统启动时创建自定义容器简单例子

    在这个例子中,我们将探讨如何利用Servlet监听器在系统启动时创建一个自定义容器。 首先,我们需要了解Servlet监听器的概念。Servlet监听器是实现了Java Servlet API中特定接口的类,这些接口定义了对Web应用生命...

    Jetty 9 Servlet容器

    总的来说,Jetty 9 Servlet容器以其轻量级、高效和灵活的特性,成为了Java Web开发中一个值得信赖的选择。无论是小型项目还是大型企业级应用,都能从中受益。通过深入理解和熟练掌握Jetty 9,开发者可以构建出更强大...

    JAVA WEB中Servlet和Servlet容器的区别

    "JAVA WEB中Servlet和Servlet容器的区别" 在 Java Web 开发中,Servlet 和 Servlet 容器是两个非常重要的概念,但是很多人对它们的区别却不甚了解。本文将对 Servlet 和 Servlet 容器进行详细的介绍,并阐述它们...

    Tomcat(全称为Apache Tomcat)是一个开源的Java Servlet容器,由Apache软件基金会下属的Jaka

    tomcatTomcat(全称为Apache Tomcat)是一个开源的Java Servlet容器,由Apache软件基金会下属的Jakarta项目开发。Tomcat实现了Java Servlet、JavaServer Pages(JSP)和Java Expression Language(EL)等Java技术,...

    Servlet项目实践 实现学生信息系统的全部代码

     1、编写一个Java类,实现servlet接口。  2、把开发好的Java类部署到web服务器中。  按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet 二、Servlet的运行过程 Servlet程序...

    jetty轻量级servlet容器

    Jetty 是一个用 Java 实现、开源、基于标准的,并且具有丰富功能的 Http 服务器和 Web 容器,可以免费的用于商业行为。Jetty 这个项目成立于 1995 年,现在已经有非常多的成功产品基于 Jetty,比如 Apache Geromino...

    servlet实现的一个简单web程序

    总的来说,"servlet实现的一个简单web程序"是一个学习和实践Servlet技术的好项目,涵盖了Web开发中基础且重要的方面。通过这样的项目,开发者可以深入理解Servlet的工作原理,以及如何利用Servlet构建交互式的Web...

    简单的servlet例子

    总结来说,这个简单的Servlet示例展示了如何创建一个基础的Servlet,处理请求并返回响应。通过配置`web.xml`,我们可以控制Servlet如何在Web应用中被加载和映射。这对于初学者理解Servlet的工作原理和生命周期至关...

Global site tag (gtag.js) - Google Analytics