其余更多java基础文章:
java基础学习(目录)html
Servlet是一个特殊的Java类, 是运行在 Web 服务器中的小型 Java 程序(即:服务器端的小应用程序)。servlet 一般经过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。这个Java类必须继承HttpServlet。每一个Servlet能够响应客户端的请求,Servlet提供不一样的方法用于响应客户端请求,例如doGet,doPost,doPut等java
Tomcat 是Web应用服务器,是一个Servlet/JSP容器. Tomcat 做为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户.而Servlet是一种运行在支持Java语言的服务器上的组件.。web
Servlet最多见的用途是扩展Java Web服务器功能,提供很是安全的,可移植的,易于使用的CGI替代品。 从http协议中的请求和响应能够得知,浏览器发出的请求是一个请求文本,而浏览器接收到的也应该是一个响应文本。 spring
Java Servlet API 是Servlet容器(tomcat)和servlet之间的接口,它定义了serlvet的各类方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。因此说咱们在编写servlet时,须要实现Servlet接口,按照其规范进行操做。浏览器
在浏览器的地址栏输入:http://ip:port/appNames/servlet缓存
1)经过浏览器和ip:port和这个服务器创建链接。
2) 浏览器会生成一个请求数据包(路径appNames/servlet)向服务器发送请求。
3) 服务器收到请求数据包,分析请求资源路径作精准定位,经过请求的appName查找webapps文件下面的appName作匹配,匹配上了须要获取web.xml中的servlet(mapping)。
4) 服务器建立两个对象:
第一个对象:请求对象,该对象实现了HttpServletRequest接口,服务器会将请求数据包中的数据解析出来,存储在该对象里。这样作的好处是没有必要理解http协议,只须要读取request。
第二个对象:响应对象,实现了HttpServletResponse接口,做用是servlet处理完成后的结果能够存放到该对象上,而后服务器依据该对象的数据生成响应数据包。
5) servlet在执行servlet()方法时,能够经过request获取请求数据,也能够将处理结果存放到response上。而后服务器与响应对象直接造成一个默契,生成一个响应数据包给浏览器。
6)浏览器解析服务器返回的响应数据包,生成响应的结果。tomcat
Servlet访问的过程:
Http请求---->web.xml--------> url -pattern----->servlet-name----->servlet-class-----> QuickStratServlet(对应的Class文件)安全
Servlet生命周期可分为5个步骤springboot
简单总结:只要访问Servlet,service()就会被调用。init()只有第一次访问Servlet的时候才会被调用。 destroy()只有在Tomcat关闭的时候才会被调用。bash
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
复制代码
@SpringBootApplication
public class ServletApp {
@Bean
public ServletRegistrationBean MyServlet(){
return new ServletRegistrationBean(new MyServlet(),"/myserv/*");
}
public static void main(String[] args){
SpringApplication.run(ServletApp.class, args);
}
}
复制代码
#Servlet细节
当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径做为servlet的映射url,好比我访问的是http://localhost/hiway/user/aaa.html,个人应用上下文是hiway,容器会将http://localhost/hiway去掉,剩下的/user/aaa.html部分拿来作servlet的映射匹配。这个映射匹配过程是有顺序的,并且当有一个servlet匹配成功之后,就不会去理会剩下的servlet了。其匹配规则和顺序以下:
在Servlet规范中,对于Servlet单例与多例定义以下:
“Deployment Descriptor”, controls how the servlet container provides instances of the servlet.For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.
上面规范提到: 若是一个Servlet没有被部署在分布式的环境中,通常web.xml中声明的一个Servlet只对应一个实例。 而若是一个Servlet实现了SingleThreadModel接口,就会被初始化多个实例。默认20个
因此我的理解Servlet不算单例,只是容器让它只实例化一次,变现出来的是单例的效果而已
对上面的三种方法进行测试,能够代表用它们都能设计出线程安全的Servlet程序。可是,若是一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每一个新的请求建立一个单独的Servlet实例,这将引发大量的系统开销。SingleThreadModel在Servlet2.4中已再也不提倡使用;一样若是在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大降低。这是由于被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量下降,并且不少客户处于阻塞状态。另外为保证主存内容和线程的工做内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。因此在实际的开发中也应避免或最小化 Servlet 中的同步代码;**在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。**从Java 内存模型也能够知道,方法中的临时变量是在栈上分配空间,并且每一个线程都有本身私有的栈空间,因此它们不会影响线程的安全
在servlet的配置当中,
<load-on-startup>1</load-on-startup>
复制代码
的含义是:
标记容器是否在启动的时候就加载这个servlet。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。
配置load-on-startup后,servlet在startup后当即加载,但只是调用servlet的init()方法,用以初始化该servlet相关的资源。初始化成功后,该servlet可响应web请求;如未配置load-on-startup,容器通常在第一次响应web请求时,会先检测该servlet是否初始化,如未初始化,则调用servlet的init()先初始化,初始化成功后,再响应请求。
能够将url-pattern 配置一个/,表明该servlet是缺省的servlet。什么是缺省的servlet? 当你访问资源地址全部的servlet都不匹配时,缺省的servlet赋值处理。其实,web应用中全部的资源的响应都是servlet负责,包括静态资源(html页面)。(有配置缺省的servlet,没法访问到静态资源。)