一、如何开发一个Servlet
1、编写Java类,继承HttpServlet类(为什么要继承这个HttpServlet类呢?所有的Servlet类都要实现Servlet接口,GenericServlet实现了Servlet接口,但是这个类没有具体协议,所以HttpServlet继承了GenericServlet类,因此我们在编写Servlet类的时候,我们只需继承HttpServlet类,覆盖里边我们要用到的方法就可以。)
2、重写doGET()和doPost方法
3、Servlet程序由tomcat服务器运行。
3.1 Servlet程序的class码拷贝到WEB-INF下边的classes目录里
3.2 在web.xml 文件中进行配置
部署web.xml文件
由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工 作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servelet> <!-- 给Servlet取名,可以任意取名 --> <servelet-name>Hello</servelet-name> <!-- 指明servlet的路径,就是servlet的包+类名 --> <servlet-class>com.lyjs.Hello</servlet-class>
</servelet>
<servelet-mapping> <!-- servlet的内部名称,一定要和上面的内部名称保持一致!! --> <servelet-name>Hello</servelet-name> <!-- 浏览器中输入的url,可以随意取名 -->
<url-pattern>/Hello</url-pattern>
</servelet-mapping>
3.3一对多映射
同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。这样就可以通过不同的URL来访问同一个Servlet。
<!--Hello被映射到/Hello--> <servelet-mapping> <servelet-name>Hello</servelet-name> <url-pattern>/Hello</url-pattern> </servelet-mapping> <!--Hello被映射到/My/Hello--> <servelet-mapping> <servelet-name>Hello</servelet-name> <url-pattern>/My/Hello</url-pattern> </servelet-mapping> <!--所以可以通过两个URL,都可以访问到Hello这个Servlet-->
3.4、映射匹配问题:
url-pattern 浏览器输入 精确匹配 /first http://localhost:8080/day10/first /itcast/demo1 http://localhost:8080/day10/itcast/demo1 模糊匹配
/* http://localhost:8080/day10/任意路径 /itcast/* http://localhost:8080/day10/itcast/任意路径 *.后缀名 http://localhost:8080/day10/任意路径.do *.do *.action *.html(伪静态)
注意:
- url-pattern要么以 / 开头,要么以 * 开头,例如:itlyjs 为非法路径。
- 在Servlet中模糊匹配有两种固定的形式:一种是"*.扩展名",另一种是以正斜杠(/)开头并以"/*"结尾。不能同时使用两种模糊匹配,要么/* ,要么 *.do. 例如 /itlyjs/*.do是非法路径。
- 当有输入的URL有多个Servlet同时匹配的时候:精确匹配优先,(长的最像的优先匹配,),以后缀名结尾的模糊url-pattern优先级最低
练兵场地
- Servlet1 映射到 /abc/*
- Servlet2 映射到 /*
- Servlet3 映射到 /abc
- Servlet4 映射到 *.do
问题:
- 当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应,Servlet引擎将调用Servlet1。
- 当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应,Servlet引擎将调用Servlet3。
- 当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应,Servlet引擎将调用Servlet1。
- 当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应, Servlet引擎将调用Servlet2。
- 当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应, Servlet引擎将调用Servlet2。
优先级:完全匹配>*匹配>后缀名匹配
四、Servlet缺省路径
servlet的缺省路径(<url-pattern>/</url-pattern>)是在tomcat服务器内置的一个路径。该路径对应的是一个DefaultServlet(缺省Servlet)。这个缺省的Servlet的作用是用于解析web应用的静态资源文件。
问题: URL输入http://localhost:8080/day10/index.html 如何读取文件?
- 到当前day10应用下的web.xml文件查找是否有匹配的url-pattern。
- 如果没有匹配的url-pattern,则交给tomcat的内置的DefaultServlet处理
- DefaultServlet程序到day10应用的根目录下查找是存在一个名称为index.html的静态文件。
- 如果找到该文件,则读取该文件内容,返回给浏览器。
- 如果找不到该文件,则返回404错误页面。
总结:web应用的资源分为两类,动态资源和静态资源。tomcat先找动态资源,再找静态资源
五、Servlet的生命周期
- 构造方法:创建Servlet对象的时候调用。默认情况下,第一次访问Servlet的时候创建Servlet对象,只调用1次。证明Servlet对象在tomcat是单例的。
- init方法:创建完Servlet对象的时候调用,只调用1次
- service方法:每次发出请求时调用1次。调用n次
- destory方法:销毁Servlet对象的时候调用,停止服务器或重新部署web应用时销毁Servlet对象,只调用1次。
文字描述:(可以跳过)
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调 用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个 新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service 方法再根据请求方式分别调用doXXX方法。
六、伪代码演示Servlet的生命周期
Tomtcat内部代码运行:
1)通过映射找到到servlet-class的内容,字符串: gz.itcast.a_servlet.FirstServlet
2)通过反射构造FirstServlet对象
2.1 得到字节码对象
Class clazz = class.forName("gz.itcast.a_servlet.FirstServlet");
2.2 调用无参数的构造方法来构造对象
Object obj = clazz.newInstance(); ---1.servlet的构造方法被调用
3)创建ServletConfig对象,通过反射调用init方法
3.1 得到方法对象
Method m = clazz.getDeclareMethod("init",ServletConfig.class);
3.2 调用方法
m.invoke(obj,config); --2.servlet的init方法被调用
4)创建request,response对象,通过反射调用service方法
4.1 得到方法对象
Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
4.2 调用方法
m.invoke(obj,request,response); --3.servlet的service方法被调用
5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
5.1 得到方法对象
Method m = clazz.getDeclareMethod("destroy",null);
5.2 调用方法
m.invoke(obj,null); --4.servlet的destroy方法被调用
七、Servlet的自动加载:<load-on-startup>
默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
<servlet> <servlet-name>invoker</servlet-name> <servlet-class> org.apache.catalina.servlets.InvokerServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet>
标签里边的数字代表了调用的优先级,数字越小,越先被调用。
八、Servlet线程安全问题。
注意: Servlet对象在tomcat服务器是单实例多线程的。
因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。
解决办法:
- 把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
- 建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。
九、ServletConfig对象,学习ServletConfig对象(点击我,去学习)
十、ServletContext对象,学习ServletContext对象(点击我,去学习)