写Web应用时,直接用的spring框架,没有接触过Servlet,于是遇到问题不知道根本原因,所以还是学一下吧!
一、 什么是Servlet
看见这个词我就晕,到底是什么?我试着说清楚,从大的方面来说,它是一个在Web中生成动态内容的标准,即是用于开发Web应用程序的基本技术;从小的方面来说它是Java提供的一个接口Servlet,我们也把实现这个接口的类称为Servlet。它和CGI相对,但是它不向CGI一样每次接受一个Http请求都会创建一个进程(想想Chrome),它每次执行完它的第一个请求之后都会驻留在内存中,等待后续的请求。
一个Servlet应用程序经常包括一个或者多个Servlet,Servlet是运行在Servlet容器中的,它不能自动运行。Servlet容器又是什么东西?我的理解就是实现了Servlet规范,然后暴露出来一些编程的接口供我们实现自己的逻辑,所以每个自定义的Servlet类都要实现Servlet接口,它能够生成动态的内容,不向Web服务器一样,只是提供静态资源。更细节的内容看如下的相关文章。Servlet容器将用户的请求传给Servlet应用程序,并将Servlet应用程序的响应回传给用户。比较流行的Servlet容器有Tomcat和Jetty。这两个本质上是Servlet容器 ,而不是Web服务器,但是它们把Web服务器要做的工作也集成到容器中了,所以不需要额外的Web服务器。
二、 Servlet API
我使用的是Servlet的3.1.0版本,有4个Java包:
javax.servlet:包含Servlet与Servlet容器进行通信需要的类和接口,比如请求、响应、过滤和监听等;
javax.servlet.http:包含Servlet的实现类httpServlet与Servlet容器进行通信需要的类和接口;
javax.servlet.annotation:使用Servlet、Filter和Listener时需要的注解;
javax.servlet.descriptor:提供对配置信息进行编程式访问的类型;
在Servlet技术的核心当然是Servlet接口,每个自定义的类都是直接或者间接实现了这个接口。在这个接口中说明了Servlet怎么被Servlet容器调用,首先容器会把Servlet类加载到内存中,并在Servlet类调用特定的方法,在每个应用程序中,每个Servlet只有一个实例(单实例)。下面试一下Servlet中的方法:
- public class TestServlet implements Servlet {
- private transient ServletConfig servletConfig;
- public void init(ServletConfig config) throws ServletException {
- this.servletConfig = config;
- System.out.println("init");
- }
- public ServletConfig getServletConfig() {
- return servletConfig;
- }
- public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
- System.out.println("service");
- }
- public String getServletInfo() {
- return this.servletConfig.getServletName();
- }
- public void destroy() {
- System.out.println("destroy");
- }
- }
- @WebServlet(name="testServlet", urlPatterns="/testServlet",loadOnStartup=-1)
- public class TestServlet implements Servlet {}
通过web.xml配置:
- <servlet>
- <servlet-name>TestServlet</servlet-name>
- <servlet-class>com.javaservlet.servlet.TestServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>TestServlet</servlet-name>
- <url-pattern>/TestServlet</url-pattern>
- </servlet-mapping>
注意:
配置url-pattern时,可以对一个Servlet配置多个url,也就是可以通过多个url来访问同一个servlet;
配置url-pattern时,也可以使用通配符进行配置,但是只有两种固定方法:一是“*.扩展名”,类似“*.html”;另外一个则是以“/”开头,以“/*”结尾,类似“/test/*”;
启动Servlet容器,这里我们使用Tomcat,经过多次使用浏览器发送请求,输出如下:
Servlet接口中有三个生命周期方法:
init():刚启动Servlet容器时不会调用这个方法,当第一次请求来的时候才会调用该方法,其实什么时候调用由loadOnStartup属性决定,如果是非0值则该方法会在容器启动时被调用,但是该值默认是-1,在后续的请求时不会再调用该方法,所以说在该方法中进行程序初始化相关的代码,另外值得注意的是该方法总是在servlet的构造器之后运行;
service():每次请求Servlet时候,Servlet容器会调用这个方法,是具体编写业务逻辑的地方;
destroy():销毁Servlet的时候,Servlet容器会调用这个方法,发生在卸载应用程序或者关闭Servlet容器时,另外从上面的输出来看,每次修改代码后保存都会reload,这个时候其实销毁该Servlet类,关闭Servlet容器并重新开启,可以在这个方法中进行资源清理的工作;
该接口中还有其他两个非生命周期的方法:getServletInfo()感觉不是很常用,只是返回对Servlet的描述;getServletConfig()返回init()传入的ServletConfig类实例,是关于Servlet的配置信息。
由于Servlet实例是单实例,在每一个应用程序中,多次请求都是针对一个对象,很容易造成并发问题,所以可以把它当做只读的,或者使用java并发机制中成员。