作为servlet
本篇对应《head first servlet and jsp》的第四章。该章节通过servlet为引子,讲解了请求和响应。从这一章中应该更加清楚的认识到servlet在MVC中应该扮演的是controller的角色。
因为该章大部分的篇幅在API的介绍上,这些部分就请读者自行翻阅吧。
当然也意味着,我的这篇博客变短了 இ௰இ
servlet的一生
servlet的证明周期很简单,当然这些都是由容器来管理的,我们并不是非常需要关注他们的。这里的例子沿用上一篇博客的servletStudy吧
Web容器 | servlet类 | servlet对象 |
---|---|---|
加载类 | servletStudy.class | 还不存在呢 |
实例化servlet(构造函数运行中) | 没你事了😫 | 对象初现👶 |
初始化函数init() | 😫 | 初始化👦 |
service() | 😫 | 处理客户请求💪 |
destroy() | 😫 | 生命结束了👴 |
以上方法都继承自Servlet接口,不过你自己写servlet的时候继承的是HttpServlet,然后HttpServlet又继承自GenericServlet,最后是GenericServlet实现了Servlet接口并覆盖了init方法。关系还是蛮复杂的嘛(◎﹏◎)
之前说到容器会为每个servlet创建一个独立的线程,那么在这个线程里去处理客户的请求吗(◎﹏◎)?
servlet的线程
我们的servlet实例永远只会起一个线程(我说的当然是一个servlet类只会起一个线程)(●ˇ∀ˇ●)那么当用户A发起一个请求1后,容器为其创建一个线程A之后。在那之后用户B发起一个请求1
疑问1
那么用户B是进入到线程A来吗?
回答是❌,实际上每一个请求都在一个单独的线程中运行!容器会为用户B创建一个线程B来处理这个请求1。
疑问2
这时或许会有一个疑问,如果用户A又发起了一个请求2,那么这个请求2是进入到线程A里面吗?
很可惜回答又是❌,我们仔细的看看这句话。
实际上每一个请求都在一个单独的线程中运行!
我想你的心中已经有了答案💡吧?
虽然请求2是用户A发出的,但是这跟他是用户A还是用户B发出的没有任何关系哦,所以事实上容器会创建线程C来处理请求2。
疑问3
这时又有人提出了一个问题,如果容器使用了集群,这个应用分在了很多JVM上,那么情况是怎么样的呢?
这个问题的答案非常的简单,每个JVM做的事情都跟上面说的一样,使用了集群不过是 J V M ∗ N JVM*N JVM∗N罢了。
也就说如果上面的情况不论出现在了JVM1或在JVM2或者是JVMn处理方式都是一样的。
每个特定servlet在这个每个JVM中都有且仅有一个实例,并且JVM会为该servlet的请求创建独立的线程。
ServletConfig和ServletContext
详细的将会在下一章介绍
ServletConfig
- 每个servlet有一个ServletConfig对象
- 用于向servlet传递部署时信息
- 用于访问ServletContext
- 参数在部署描述文件中配置
ServletConfig是一个接口由GenericServlet实现并作为其成员。但是我们先把目光放到ServletConfig接口吧。
我们进入ServletConfig再看看。记住这些方法名,可以看到这些方法都在GenericServlet中得到了实现。
package javax.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
我们来看看GenericServlet,我摘取了需要讲解的部分,这并不是GenericServlet的全部哦`(>﹏<)′
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
private transient ServletConfig config;
public void init(ServletConfig config) throws ServletException {
//每个servlet有一个ServletConfig对象
this.config = config;
this.init();
}
public ServletConfig getServletConfig() {
return this.config;
}
public String getServletName() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletName();
}
}
//用于访问ServletContext
public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}
public Enumeration getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}
public Enumeration getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}
}
ServletContext
-
每个应用有一个ServletContext
-
用于访问Web应用参数
-
相当于应用中的一个公告栏,可以在这里放消息(称之为属性),应用的其他部分可以访问这些消息
-
用于得到服务器信息,包括容器的名字和版本以及所支持的API版本等
我们把目光放回到ServletConfig这个接口
package javax.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
看到第2个方法了吗?获取ServletContext就是从这里,那么ServletContext干了什么呢?就自己去看源码吧,下一章会讲的(*^_^*)
OK 话题好像扯远了呢?┗|`O′|┛ 嗷~~ 虽然好像我们一直在说的都是servlet。但是从这里开始《head first servlet and jsp》说的都是关于请求和响应了,请求就是GET和POST这些,而这些并不是我这篇博客想要说的东西,想要了解的话就去阅读该书📕的第4章剩余部分吧。接下来的内容只是一些记录的笔记而已了。
也就是说从这里开始,你已经可以点❌离开这篇博客了,下面是我的个人时间🕐
曾经遇到的一个问题
在某个视频中学重定向的时候,对于URL路径的设定出了点问题导致出现了404,在阅读到这里后找到了答案💡,果然看书📕还是很棒的
在使用sendRedirect方法时使用相对路径有2种
- 前面有斜线👉👉👉/
- 前面没有斜线
以我的博客地址为例吧https://highway2020.life(疯狂明示😋😋😋)
我们现在进入将一个请求发送至一个叫hello.do的servlet
https://highway2020.life/hello/hello.do
我们在这个servlet里发现无法处理这个请求,需要重定向到另外一个页面
sendRedirect("help/help.html");
容器会相对于原先的URL请求建立完整的URL ,用通俗的话来说就是会在拼接到原请求URL的后面,重定向的URL是这样的
https://highway2020.life/hello/help/help.html
但是如果我们是用斜线开头的呢?
sendRedirect("/help/help.html");
容器会相对于Web应用本身建立完整的URL ,用通俗的话来说就是会在拼接到Web应用URL的后面,重定向的URL是这样的
https://highway2020.life/help/help.html