初学JavaWeb开发,请远离各种框架,从Servlet开始。
Web框架是开发者在使用某种语言编写Web应用服务端是关于架构的最佳实践。很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处理有关,形成一个基础,在开发别的应用项目的时候则可以从这个剥离出来的基础做起,让开发者更关注具体的业务问题,而不是Web的请求和响应的控制。
框架很多,但套路基本类似,帮你隐藏很多关于HTTP协议细节内容,专注功能开发。
但对于一个初学者来说,过早的接触框架往往事倍功半!同样一个问题,换一种框架你可能需要从头开始研究。
所以,作为Java Web技术的核心基础,Servlet的工作原理是必须掌握的,也是成为一名合格的Java Web技术开发人员的基本要求。
一、Servlet简介
Servlet是Server与Applet的缩写,是服务端小程序的意思。是SUN公司提供的一门用于开发动态Web资源的技术。目前最新版本为3.1。
Servlet本质上也是Java类,但要遵循Servlet规范进行编写,没有main()方法,它的创建、使用、销毁都由Servlet容器进行管理(如Tomcat)。
Servlet是和HTTP协议是紧密联系的,其可以处理HTTP协议相关的所有内容。这也是Servlet应用广泛的原因之一。
提供了Servlet功能的服务器,叫做Servlet容器,其常见容器有很多,如Tomcat, Jetty, resin, Oracle Application server, WebLogic Server, Glassfish, Websphere, JBoss等。
二、Servlet工作原理解析
1、一个HTTP请求的执行过程:
根据Web.xml文件的配置,找到<url-pattern>对应的<servlet-mapping>
读取<servlet-mapping>中<servlet-name>的值
找到<servlet-name>对应的<servlet-class>
找到该class并加载执行该class
2、Servlet的执行过程
Servlet程序有Web服务器调用,当收到请求后,
检查是否已装载并创建了该Servlet对象,如果没有则加载创建
调用Servlet的init()方法初始化实例
调用service()方法,处理请求并返回响应结果
在服务器被停止或重启之前,调用destroy()方法释放资源
3、Servlet接口实现类
SUN公司定义了两个实现类,GenerricServlet和HttpServlet,其中后者是前者的子类,它在原有基础上添加了一些HTTP协议处理方法,它比GenerricServlet功能更强大,所以我们一般将自己的类继承自HttpServlet,并重写doGet方法和doPost方法,不需要重写Service方法。
4、Servlet的一些细节
4.1、由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序弱项被外界访问,必须把Servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成(在Servlet3.0规范的新特性中,该功能可以使用注解完成,不要求必须使用web.xml,只用注解更简单,该特性会在后文进行详细讲解)。
<servlet>元素用于注册Servlet,它包含两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
<web-app>
<servlet>
<servlet-name>AnyName</servlet-name><!--自定义的逻辑名-->
<servlet-class>HelloServlet</servlet-class><!--Servlet对应类的全类名-->
</servlet>
<servlet-mapping>
<servlet-name>AnyName</servlet-name><!--上面定义的逻辑名-->
<url-pattern>/demo/hello.html</url-pattern><!--匹配的URL-->
</servlet-mapping>
</web-app>
4.2、同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:
一种是“*.扩展名”。
另一种是以(/)开头并以(/*)结尾。
<!--方式一用于匹配所有某一扩展名的文件-->
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!--方式二用于匹配某一文件夹下的所有文件-->
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
两个特点:可以精确匹配,就用精确匹配,最后使用范围最宽泛的匹配
/* 的优先级高于 *.扩展名 会先匹配
4.3、如果某个Servlet的映射路径只有一个(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的请求访问都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
在tomcat的安装目录/conf/web.xml中,注册了一个名称org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为缺省Servlet。
当访问Tomcat服务器中的某个静态HTML文件或图片等资源时,实际上是在访问这个缺省Servlet。
5、Servlet的生命周期
Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会在第一次请求的时候创建一个Servlet实例对象,并驻留在内存中,为后续的其他请求服务,直至web容器退出,Servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init()方法只被调用一次,而对于每一个请求都会调用一次Servlet的service()方法service根据请求方式调用doGet或doPost方法
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建实例对象、以及调用Servlet实例对象的init()方法。可以在启动的时候为整个WEB应用创建一些必要的的资源或连接。但如果所有的Servlet都启动加载,则会大大增加服务器负担,而且有些Servlet永远也不会被客户访问到,白白浪费资源,所以从性能角度,应合理利用该特性。
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>2</load-on-startup><!--数字表示启动加载的优先级,大于0-->
</servlet>
6、ServletConfig对象
在Servlet的配置文件中,可以使用一个或对个<init-param>标签为Servlet配置一些初始化参数。
当Servlet配置了初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init方法时,将ServletConfig对象传似给Servlet,开发者可以通过ServletConfig对象得到初始化参数信息。
7、ServletContext对象
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的Servlet对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发者在编写Servlet是,可以通过ServletConfig.getServletContext方法获得该对象。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为Context域对象。
多个Servlet通过ServletContext对象实现数据共享。要确保注意线程安全。
可以通过ServletContext对象获取WEB应用的初始化参数。
可以实现Servlet的转发。getRequestDispatcher()方法
8、Servlet常用容器Tomcat(左图:Tomcat容器;右图:Servlet的执行流程)
9、Servlet体系结构
从上图可以看出Servlet规范是基于这几个类运转的,与Servlet主动关联的是三个类:ServletConfig、ServletRequest、ServletResponse。这三个类都是通过容器传递给Servlet的。
ServletConfig接口中的方法都是为了获取这个Servlet的一些配置属性,而这些配置属性可能在Servlet运行时被用到。
ServletContext就是这些配置属性的上下文环境。
三、Servlet中的Session与Cookie
Servlet能够给我们提供两部分数据,一个是在Servlet初始化时调用init方法设置的ServletConfig,它基本包含了Servlet本身和Servlet所运行的Servlet容器中的基本信息。另一个是ServletRequest提供的这次请求的HTTP协议信息,这部分需要很清楚HTTP协议。
Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态,各有优缺点。然而具有讽刺意味的是它们优点和它们的使用场景又是矛盾的,例如使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿的时候,它要占用多少带宽。所以大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。
Session正常工作的实现方式:
基于URL Path Parameter,默认支持
基于Cookie,若不修改Context中的cookie标识,默认支持
基于SSL,默认不支持,只有connector.getAttribute("SSLEnabled")为true时才支持。
四、Servlet中的Listener
整个Tomcat服务器中Listener使用的非常广泛,它是基于观察者模式的,Listener的设计对开发Servlet应用程序提供了一种快捷的手段,能够方便的从另一个纵向唯独控制程序和数据,目前Servlet中提供了5中两类事件的观察者接口,他们分别是:4个EventListener类型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 个 LifecycleListeners 类型的,ServletContextListener、HttpSessionListener。
它们基本上涵盖了整个Servlet生命周期中,你感兴趣的每种事件,这些Listener的实现类可以配置在web.xml中的<listener>标签中,当然也可以在应用程序中动态添加Listener,但是ServletContextListener在容器启动之后就不能再添加新的,因为它监听的事件已经不会再出现。掌握这些Listener的使用,能够让我们的程序设计的更加灵活。
五、Servlet3.0新特性注解
前面介绍过Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署描述。
开发者可以使用@WebServlet注解将一个继承于javax.servlet.http.HttpServlet的类标注为可以处理用户请求的Servlet。
@WebServlet注解的相关属性 |
NO. |
属性名 |
描述 |
1 |
asyncSupported |
声明Servlet是否支持异步操作模式 |
2 |
description |
Servlet的描述信息 |
3 |
displayName |
Servlet的显示名称 |
3 |
initParams |
Servlet的初始化参数 |
5 |
name |
Servlet的名称 |
6 |
urlPatterns |
Servlet的访问URL |
7 |
value |
Servlet的访问URL |
Servlet的访问URL是Servlet的必选属性,可以选择使用urlPatterns或者value定义。
更多关于Servlet3.0的注解使用知识请参考博客:
- 走进JavaWeb技术世界开篇:JavaWeb技术汇总
微信公众号[Java技术江湖]一位阿里 Java 工程师的技术小站.(关注公众号后回复”Java“即可领取 Java基础.进阶.项目和架构师等免费学习资料,更有数据库.分布式.微服务等热门技术学习视频 ...
- 走进JavaWeb技术世界1:JavaWeb的由来和基础知识
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- Servlet---JavaWeb技术的核心基础,JavaWeb框架的基石(二)
一.Servlet之Request Web服务器会对收到的每一次客户端http请求分别创建一个用于代表请求的request对象和代表响应的response对象.要获取客户端提交的数据需 ...
- 走进JavaWeb技术世界11:单元测试框架Junit
JUnit你不知道的那些事儿 转自 老刘 码农翻身 2016-02-24 话说有一次Eric Gamma 坐飞机的时候偶遇Kent Beck(对,就是极限编程和TDD的发起人) , 两位大牛见面寒暄 ...
- JavaWeb框架的基石
JavaWeb框架的基石(一) 初学JavaWeb开发,请远离各种框架,从Servlet开始. Web框架是开发者在使用某种语言编写Web应用服务端是关于架构的最佳实践.很多Web框架 ...
- Java工程师学习指南第2部分:JavaWeb技术世界
本文整理了微信公众号[Java技术江湖]发表和转载过的Java Web优质文章,想看到更多Java技术文章,就赶紧关注吧. IDEA中的Maven实战 老师,免费版的IDEA为啥不能使用Tomcat? ...
- 深入JavaWeb技术世界15:深入浅出Mybatis基本原理
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 走进JavaWeb技术世界14:Mybatis入门
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 走进JavaWeb技术世界3:JDBC的进化与连接池技术
走进JavaWeb技术世界3:JDBC的进化与连接池技术 转载公众号[码农翻身] 网络访问 随着 Oracle, Sybase, SQL Server ,DB2, Mysql 等人陆陆续续住进数据库 ...
随机推荐
- oracle返回多结果集
kavy 原文 oracle返回多结果集 Oracle存储过程: create or replace procedure P_Sel_TopCount2(in_top in number, out_c ...
- RESTLET开发实例(一)基于JAX-RS的REST服务
RESTLET介绍 Restlet项目为“建立REST概念与Java类之间的映射”提供了一个轻量级而全面的框架.它可用于实现任何种类的REST式系统,而不仅仅是REST式Web服务. Restlet项 ...
- [持续更新]android stduio的一些小技巧
1.导入第三方jar 无法和eclipse一样可以直接刷新就可以导入libs里的jar,要到jar文件上右键按add jar. 2.其他依赖项目里有support-v4包的时候 在Libs里还是要有s ...
- linux常用命令之--用户与用户组管理命令
linux的用户与用户组管理命令 1.用户和群组 groupadd:用于添加新的组群 其命令格式如下: groupadd [-option] 群组名 常用参数: -g GID:指定创建群组的GID(G ...
- 使用Redis的理由
Redis是一个远程内存数据库,它不仅性能强劲,而且还具有复制特性以及为解决问题而生的独一无二的数据模型.Redis提供了5种不同类型的数据结构,各式各样的问题都可以很自然地映射到这些数据结构上:Re ...
- 帮同事写了几行代码,在 安装/卸载 程序里 注册/卸载 OCX控件
写了个小控制台程序,这个程序用来注册 / 卸载OCX控件,用在Inno Setup做的安装卸载程序里. #include "stdafx.h" #include <windo ...
- lighttpd+fastcgi模块分析
一开始不怎么明白fastcgi和cgi的区别,查了资料说,fastcgi多了一个进程池,不要每次都fork和退出 这个不是重点,还是对着代码看吧 怎样在lighttpd运行php呢,需要下面这样配置 ...
- bzoj4578: [Usaco2016 OPen]Splitting the Field
2365: Splitting the Field 题意:n个点,求用两个矩形面积覆盖完所有点和一个矩形覆盖完少多少面积 思路:枚举两个矩形的分割线,也就是把所有点分成两个部分,枚举分割点:先预处理每 ...
- 树莓派使用8188eu无线网卡
#已经集成了8188eu驱动的镜像 http://cassidy.pi3g.com/rpi_images/raspbian-wifi-fix130523.7z #需要修改的信息 sudo nano / ...
- HDU-4720 Naive and Silly Muggles 圆的外心
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4720 先两两点之间枚举,如果不能找的最小的圆,那么求外心即可.. //STATUS:C++_AC_0M ...