Servlet

Servlet是Server+Applet的缩写,表示一个服务器应用。
其实就是一套规范,我们按照这套规范写的代码就可以直接在Java的服务器上面运行
为什么可以?因为Java的服务器也是按这规范写的

Servlet接口

既然Servlet是一套规范,那么最重要的当然就是接口了

//javax.servlet.Servlet
public interface Servlet{
	public void init(ServletConfig config) throws ServletException;
	public ServletConfig getServletConfig();
	public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException;
	public String getServletInfo();
	public void destroy();
}

init()在容器启动时被窗口调用(当load-on-startup设置为负数或者不设置时会在Servlet第一
次用到时才被调用),只会调用一次;
getServletConfig()用于获取ServletConfig;
service()用于具体处理一个请求;
getServletInfo方法可以获取一些Servlet相关的信息,如作者、版权等,这个方法需要自己实现,默认返回空字符串
destroy()主要用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次

Init方法被调用时会接收到一个ServletConfig类型的参数,是容器传进去的。
Selvet-Config顾名思义指的是Servlet的配置
我们在web.xml中定义Servlet时通过init-param标签配置的参数就是通过ServletConfig来保存的,比如,定义SpringMVC的Servlet时指定配置文件位置的contextConfigLocation参数就保存在ServletConfig中

<servlet>
	<servlet-name>实例名</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>demo-servlet.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

Tomcat中Servlet的init方法是在org.apache.catalina.core.StandardWrapper的initServlet
方法中调用的,ServletConfig传入的是StandardWrapper(里面封装着Servlet)自身的门面类StandardWrapperFacade。
其实这个也很容易理解,Servlet是通过xml文件配置的,在解析xml时就会把配置参数给设置进去,这样StandardWrapper本身就包含配置项了,当然,并不是StandardWrapper的所有内容都是Config相关的,所以就用了其门面Facade类

//ServletConfig接口
package javax.servlet;
public interface ServletConfig{
	//获取Servlet的名字,在web.xml中定义的<servlet-name>名字</servlet-name>
	public String getServletName();
	//非常重要
	public ServletContext getServletContext();
	//用于获取<init-param></init-param>配置的参数
	public String getInitParameter(String name);
	//获取所有init-param的名字集合
	public Enumeration<String> getInitParameterNames();
}
getServletContext()非常重要,它的返回值ServletContext代表的是我们应用本身
ServletContext其实就是Tomcat中Context的门面类ApplicationContextFacade
(具体代码参考StandardContext的getServletContext方法)。
既然ServletContext代表应用本身,
那么ServletContext里边设置的参数就可以被当前应用的所有Servlet共享了。

我们做项目的时候都知道参数可以保存在Session中,也可以保存在Application中
而后者很多时候就是保存在了ServletContext中

我们可以这么理解
ServletConfig是Servlet级的,而ServletContext是Context(也就是Application)级的
当然ServletContext的功能要强大很多,并不只是保存一下配置参数

ServletConfig 和ServletContext最见的使用之一是传递初始化参数,我们以spring配置使用的最多的contextConfigLocation参数为例来看一下

<!-- web.xml -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>application-context.xml</param-value>
</context-param>
<servlet>
	<servlet-name>DemoServlet</servlet-name>
	<servlet-class>com.excelib.DemoServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>demo-servlet.xml</param-value>
	</init-param>
</servlet>

上面通过context-param配置的contextConfigLocation配置到了ServletContext中,而通过servlet下的init-param配置的contextConfigLocation配置到的ServletConfig中。在Servlet中可以分别通过它们的getInitParameter方法来获取

String contextLocation = getServletConfig().getServletContext()
                              .getInitParameter("contextConfigLocation");
String servletLocation = getServletConfig().getInitParameter("contextConfigLocation");

另外ServletContext中非常常用的用法就是保存Application级的属性,这个可以使用setAttribute来完成,比如
getServletContext().setAttribute(“contextConfigLocation”,“new path”);
这里设置同名的Attribute并不会覆盖initParameter中的参数值,它们是两套数据,互不干扰。ServletConfig不可以设置属性

GenericServlet(通用的Servlet)

GenericServlet是Servlet的默认实现,主要做了三件事
1.实现了ServletConfig接口,我们可以直接调用里面的方法
2.提供了无参的init方法
3.提供了log方法
GenericServlet实现了ServletConfig接口,我们在需要调用ServletConfig中方法的时候可以直接调用,而不再需要先获取ServletConfig了,比如,获取ServletContext的时候可以直接调用getServletContext,而无须调用getServletConfig().getServletContext()了,不过其底层实现其实是在内部调用了,getServletContext的代码如下

//javax.servlet.GenericServlet
public ServletContext getServletContext(){
	//获取到ServletConfig
	ServletConfig sc = getServletConfig();
	if(sc != null){
		//抛出异常
   }
   return sc.getServletContext();
}

GenericServlet是与具体协议无关的

HttpServlet

HttpServlet是用HTTP协议实现的Servlet的基类,写Servlet时直接继承它就可以了,不需要再从头实现Servlet接口,SpringMVC中的DispatcherServlet就是继承的HttpServlet
即然HttpServlet是跟协议相关的,当然主要关心的是如何处理请求了
所以HttpServlet主要重写了service方法。在servic方法中首先将ServletRequest和ServletResponse转换为了HttpServletRequest和HttpServletResponse,然后根据Http请求的类型不同将请求路由到了不同的处理方法,代码如下

//java.servlet.http.HttpServlet
public void service(ServletRequest res , ServletResponse res){
	HttpServletRequest request;
	HttpServletResponse response;
	//如果请求类型不相符,则抛出异常
	if(!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)){
		//抛出异常
	}
	//转换请求的类型
	request = (HttpServletRequest) req;
	response = (HttpServletResponse) res;
	//调用http的处理方法
	service(request,response);
}
protected void service(HttpServletRequest req,HttpServletResponse resp){
	//获取请求类型
	String method  = req.getMethod();
	//将不同的请求类型路由到不同的方法去处理
	if(method.equals(METHOD_GET)){
		long lastModified = getLastModified(req);
		if(lastModified == -1){
			doGet(req,resp);
		} else {
			long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
			if(ifModifiedSince < lastModified){
				maybeSetLastModified(reqp,lastModified);
				doGet(req,resp);
			} else{
				resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			}
		}
	} else if(method.equals(METHOD_POST)){
		doPost(req,resp);
		//其他方法省略
	}
}

这就是HttpServlet,它主要将不同的请求方式路由到了不同的处理方法,不过SpringMVC中由于处理思路不一样,又将所有请求合并到了统一的一个方法进行处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值