`
0428loveyu
  • 浏览: 29136 次
  • 性别: 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容器

    [深入剖析Tomcat]一书第二章中 一个简单的servlet容器实现

    简单的servlet容器实现

    简单的servlet容器实现

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

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

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

    主要为大家详细介绍了基于Java web服务器简单实现一个Servlet容器,感兴趣的小伙伴们可以参考一下

    jetty轻量级servlet容器

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

    Tomcat中的Host和Engine级别的servlet容器.docx

    Engine容器表示Catalina的整个Servlet引擎,如果使用了Engine容器,那么它总是处于容器层级的最顶层,添加到Enginer容器中的子容器通常是org.apache.catalina.Host 或者 org.apahce.catalina.Context的实现,默认...

    Servlet过滤器使用

    这是Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后将调用这个方法。在这个方法中可以读取web.xml文件中Servlet过滤器的初始化参数。 b、doFilter(ServletRequest,ServletResponse,FilterChain)...

    spring-boot-starter-netty:一个基于Netty实现的Spring Boot内置Servlet容器。a Spring Boot embedded servlet container project base on netty API (4.1.12.Final)

    这是一个基于netty API(4.1.12.Final)的Spring Boot嵌入式servlet容器项目。 该项目已发布到Maven中心存储库中,请参阅 。 Maven依赖 将以下依赖项添加到您的Maven项目中: &lt;!-- exludes embedded Tomcat --...

    SpringBoot 注册自己的Servlet(三种方式)(源代码)

    Servlet 1,声明servlet及映射 2,加上@...目前使用Spring的,更多是在web方面,所以Spring更多的是依赖Servlet容器,哪怕是springboot擅长做独立可执行的微服务应用程序,其内部也包含一个嵌入式Jetty。

    MOTAN - the fast C++ servlet container:C ++ Servlet容器-开源

    Servlet容器以Java Servlet API 2.3为蓝本。 用C ++编写。 开发人员在动态库中实现C ++ Servlet。 包括HTTP适配器。

    使用Servlet技术响应用户请求

    Web服务器通常支持Java Servlet规范,并提供一个Servlet容器,例如Tomcat或Jetty。您可以将编译后的Servlet类文件(.class文件)部署到Servlet容器中,并在Web应用程序的web.xml文件中配置Servlet映射。

    SpringMVC 全注解实现 servlet3.0以上的容器支持.docx

    请求旅行的第一站是Spring的 ...当Web应用委托一个servlet将请求分发给应用的其他组件时,这个servlert称为 前端控制器(front controller) 。在Spring MVC中, DispatcherServlet 就是前端控制器。

    Java如何使用Jetty实现嵌入式的Servlet容器

    主要介绍了Java使用Jetty实现嵌入式的Servlet容器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起了解一下吧

    基于Java的smart-servlet Web容器设计源码

    本项目是一个基于Java语言开发的smart-servlet Web容器,包含196个文件,主要文件类型包括Java源代码、...系统设计旨在实现Servlet 3.1规范,并支持多应用隔离部署,为开发者提供了一个稳定、高效的Web应用运行环境。

    sevlet用法总结

    sevlet用法总结,很不错,学习的朋友可以看看

    java-servlet-api.doc

    JavaServletAPI提供了一个简单的接口,通过这个接口,Servlet引擎可以有效地跟踪用户的会话。 建立Session 因为HTTP是一个请求-响应协议,一个会话在客户机加入之前会被认为是一个新的会话。加入的意思是返回会话...

    基于 servlet 实现的博客系统

    该博客系统是一个基于Servlet技术开发的Web应用,旨在提供一个简单而功能完备的博客平台。用户可以注册账户、发布博客文章。整个系统使用Java Servlet技术作为后端处理逻辑,并采用MVC(Model-View-Controller)架构...

    JSP/Servlet Java面试逻辑题

    一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没有 include 动作)表示。 这既包括 servlet 又包括被编译成 servlet 的 JSP 页面。 request是代表与 Web 客户机发出的一个请求相关...

    Servlet 点击计数器

    以下是实现一个简单的基于 Servlet 生命周期的网页点击计数器需要采取的步骤: 在 init() 方法中初始化一个全局变量。 每次调用 doGet() 或 doPost() 方法时,都增加全局变量。 如果需要,您可以使用一个数据库表来...

    JAIN SLEE与SIP Servlet比较说明

    SIP Servlet是Java标准化机构JCP...SIPServlet容器的核心是SIP协议栈,容器负责接受和发送SIP消息,管理SIP对话和事务,实现SIP的核心语义。当容器收到消息时,将调用相应的SIP应用,同时SIP应用也会调用容器来发送消息。

Global site tag (gtag.js) - Google Analytics