Servlet的一些重要细节
来源:互联网 发布:tgp腾讯游戏客户端mac 编辑:程序博客网 时间:2024/05/17 06:15
1、javax.servlet.Servlet接口中的生命周期方法(即回调函数,由服务器自动调用)
- init(ServletConfig config)
service(ServletRequest request,ServletResponse response)
- destroy()
请注意格式,如在GenericServlet类中定义的init( )方法则不是生命周期方法。
2、Servlet执行过程
默认情况下,服务器会在Servlet第一次被访问时创建Servlet(你也通过修改web.xml中的配置,让服务器在启动的时候就创建出Servlet)。并且一个Servlet类型是单例的,服务器会通过反射机制只创建一个实例对象(这就会导致线程不安全问题)。在Servlet被创建之后,服务会立即调用init(ServletConfig config)方法(只会调用一次),服务器接着会调用service(ServletRequest request, ServletResponse response)方法来处理用户的请求,以及服务器做出响应。一般Servlet不会轻易被销毁,当服务器被关闭了,才会销毁Servlet,并在这之前服务器会调用destroy( )方法。
由于Servlet采用单例模式,我们第二次或以后再访问Servlet时,服务器会直接调用Service(ServletRequest request, ServletResponse response)方法。服务器接收到一次请求,就会调用service()方法一次,所以service()方法是会被调用多次的。
3、Servlet各种实现的关联
----- HttpServlet 类继承了 GenericServlet类
----- GenericServlet 类实现了 Servlet 接口
3.1 、 GeneicServlet类源码解读
package javax.servlet;import java.io.IOException;import java.util.Enumeration;public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { private transient ServletConfig config; //用来实现getServletConfig(); public GenericServlet() { // NOOP } public void destroy() { // NOOP by default } public String getInitParameter(String name) { //ServletConfig中定义的方法 return getServletConfig().getInitParameter(name); } public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } public ServletConfig getServletConfig() { return config; } public ServletContext getServletContext() { <span style="font-family: Arial, Helvetica, sans-serif;">//ServletConfig中定义的方法</span> return getServletConfig().getServletContext(); } @Override public String getServletInfo() { return ""; } public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException { //GenericServlet自己定义的方法,由于声明周期方法init(ServletConfig config)中调用了该方法,所以初始化的时候该方法也会自动被调用。 } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } public abstract void service(ServletRequest req, ServletResponse res) //需要子类自行实现该方法 throws ServletException, IOException; public String getServletName() { return config.getServletName(); }}
我们可以看到GenericServlet是一个抽象类(service是抽象方法,要我们继承的时候自己写实现方法。),并且同时还实现了ServletConfig接口。
当我们自定义Servlet时,如果想完成初始化作用就不要再重复init(ServletConfig)方法了,而是应该去重写init()方法。因为在GenericServlet中的init(ServletConfig)方法中保存了ServletConfig对象,如果覆盖了保存ServletConfig的代码,那么就不能再使用ServletConfig了。也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。
3.2、HttpServlet类的理解
HttpServlet类是在GenericServlet类的基础之上,再提供了对HTTP请求的特殊支持,所以我们在写自己的Servlet的时候一般都是继承HttpServlet。
· 在上面我们看到GenericServlet类是一个抽象类,要继承它必须实现service(ServletRequest request, ServletResponse response)方法。而在HttpServlet类中service(ServletRequest request, ServletResponse response)是这样实现的:
@Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; //将<span style="font-family: Arial, Helvetica, sans-serif;">request强转成HttpServletRequest </span> response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); //在声明周期方法中调用service(HttpServletRequest req, HttpServletResponse resp)方法 }
service(HttpServletRequest req,HttpServletResponse resp)方法的定义:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); //先获取客户端的请求方法,然后再判断,调用相应的方法。 if (method.equals(METHOD_GET)) {..... doGet(req, resp);...... } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
4、Servlet线程安全
我们不应该在Servlet中便宜创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。
只要保证没有共享的域就保证Servlet的线程线程安全,一般有如下的措施:
- 不要在Servlet中创建成员变量!创建局部变量即可;
- 可以创建没有成员变量的类作为Servlet的成员变量;
- 作为Servlet类成员变量的类可以有成员变量,但是其成员变量必须是只读的;
l Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备!
ServletConfig中的getInitParameter(String name)方法
其初始化参数在web.xml中配置如下:
<servlet> <servlet-name>FileuploadServlet</servlet-name> <servlet-class>cn.edu.jxau.servlet.FileuploadServlet</servlet-class> <init-param> <param-name>aaa</param-name> <param-value>AAA</param-value> </init-param> </servlet>
l 可以配置公共的初始化参数,为所有Servlet而用!这需要使用ServletContext才能使用!
ServletContext中的getInitParameter(String name)方法
<display-name></display-name> <context-param> <param-name>aaa</param-name> <param-value>AAA</param-value> </context-param> <servlet> <servlet-name>FileuploadServlet</servlet-name> <servlet-class>cn.edu.jxau.servlet.FileuploadServlet</servlet-class> </servlet>
- Servlet的一些重要细节
- javaweb_04,05-Servlet开发的一些重要细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- [Servlet]Servlet的一些细节
- Servlet需要注意的细节(重要)
- servlet的一些细节部分
- Servlet的一些细节问题
- Servlet的一些细节 20111018
- Servlet的一些细节2
- 第九周项目3--输出星号图
- UVa_1592 - Database
- 平衡二叉树的实现 操作 遍历
- MAC - 使用 brew 安装东西时出现 curl: (7) Failed connect to downloads.sf.net:443; Operation timed out 的解决办法
- POJ 1002 487-3279
- Servlet的一些重要细节
- iOS多线程GCD
- 电容的充电速率
- 高级控件:菜单、工具栏多窗口控制
- PHP Console工具使用分享
- MongoDB之整库备份还原单表collection备份还原
- 数据结构基础java实现—双向链表
- poj3009 冰球
- Android:圆形头像