传智播客Java web之 Servlet基础补充

    到目前为止,张老师的《深入体验Java Web开发内幕-核心基础》的第四章也就讲解完了。学完这一章之后,对servlet的认识就有了一个大概的轮廓。同时,视频中对一些关于servlet的细节知识讲解的很透彻。当了解这些细节以后,对以后写servlet时应该怎么做和为什么要这么做就有了深刻的认识。下面一些内容是对前四篇总结的补充,有如下一些内容:线程中的类加载器、servlet的线程安全问题、ServletConfig接口的补充以及init,service方法的细节。
    关于类加载器,servlet基础三从加载器的作用、策略以及Tomcat中的加载器等几个方面对视频进行了总结。下面补充一些关于线程中的类加载器的知识:
      1.如果在类A中使用new 关键字创建类B,Java虚拟机将使用加载类A的类装载器来加载类B。如果在一个类中调用Class.forName方法来动态加载另外一个类,可以通过传递给Class.forName方法的一个参数来指定另外那个类的类装载器,如果没有指定该参数,则使用加载当前类的类装载器。
      2.依据一个类的存放位置,这个类最终只能由一个特定的类装载器装载。对于一个已被父级类装载器装载的类来说,Java虚拟机默认也使用这个父级类装载器去装载它所调用的其他类,由于父级类装载器不会委托子级类装载器去装载类,所以,在一般情况下,一个已被父级类装载器装载的类无法调用那些只能被子级类装载器发现和装载的其他类。 
      3.每个运行中的线程都有一个关联的上下文类装载器,可以使用Thread.setContextClassLoader()方法设置线程的上下文类装载器。
      4.每个线程默认的上下文类装载器是其父线程的上下文类装载器,而主线程的类装载器初始被设置为ClassLoader.getSystemClassLoader()方法返回的系统类加载器。
      5.当线程中运行的代码需要使用某个类时,它使用上下文类装载器来装载这个类,上下文类装载器首先会委托它的父级类装载器来装载这个类,如果父级的类装载器无法装载时,上下文类装载器才自己进行装载。
    除了类加载器与线程有关的的补充知识点外,servlet本身的线程安全问题也需要了解一下:
      1.Servlet引擎采用多线程模式运行,它为并发的每个访问请求都使用一个独立的线程来进行响应,但带来了线程安全的问题。
      2.如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
      3.SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。
      4.对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。
      5.实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上的多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。 
    Servlet在有些情况下可能需要访问Servlet容器或借助Servlet容器访问外部的资源,所以,Serlvet引擎需要将表示Servlet容器的对象传递给Servlet。另外,在web.xml文件中为某个Servlet设置的友好名称和初始化参数等信息也需要传递给该Servlet。为了达到这个交互目的,Servlet规范定义了ServletConfig接口。该接口用于定义ServletConfig对象需要对外提供的方法,以便在Servlet程序中可以调用这些方法来获取有关信息。这样,实现Servlet规范的Servlet引擎将代表Servlet容器的对象和Servlet的配置参数信息一并封装到一个称为ServletConfig的对象中,并在初始化Servlet实例对象时传递给该Servlet。具体的就是Servlet引擎调用Servlet的实例对象的init(ServletConfig config)方法将ServletConfig对象传递给Servlet。Servlet.getServletConfig()方法必须返回init(ServletConfig config)方法传递进来的这个ServletConfig对象的引用。然而GenericServlet类已经按此要求实现了getServletConfig方法,子类如何初始化ServletConfig对象就成了一个问题:
      在Servlet程序中调用ServletConfig对象的方法举例:
        String servletName = getServletConfig().getServletName();
      GenericServlet类实现ServletConfig接口中的方法:
        public String getServletName()
        {
             return getServletConfig().getServletName();
        } 
      Servlet程序中调用ServletConfig对象的方法的简单方式举例:
        String servletName = getServletName();
      Servlet接口中定义的init方法的语法格式为:
        public void init(ServletConfig config) throws ServletException
      GenericServlet类中的其他方法依赖init方法的执行结果:
        public class GenericServlet
        {
            private ServletConfig config = null;
            public void init(ServletConfig config) throws ServletException
            {
                this.config = config;
            }
        public ServletContext getServletContext()
        {
                return config.getServletContext();
        }
        ……
}
为了不破坏GenericServlet的其他方法的功能,并且ServletConfig对象正常初始化,GenericServlet子孙类中的init方法首先应该使用super.init(config)语句。如果想不使用上述语句初始化,则有以下解决方式:
      public void init(ServletConfig config) throws ServletException
      {
          this.config = config;
          init();
      }
这样一来,ServletConfig对象既被正确初始化,同时也能够在子类中覆盖无参的init方法来进行servlet的初始化设置。同样的解决思想也反映再去爱service方法中。
      HttpServlet直接实现Servlet接口中定义的service方法,如果需要调用HttpServletRequest和HttpServletResponse中的方法则肯定要在service方法内部进行向下转型。因此只要子类覆盖该方法,就有可能要重新写转型代码。例如:
  
 public void public void service(ServletRequest req,ServletResponse res)
  throws ServletException,java.io.IOException
 {
  HttpServletRequest request = (HttpServletRequest)req;
  HttpServletResponse response = (HttpServletResponse)res;
  ……
  request.HttpServletRequest中定义的方法();
  response.HttpServletResponse中定义的方法();
  ……
 }
然而利用init采用的方法,直接在HttpServlet中重载service方法,在HttpServlet类中重写的service方法内部进行向下转型,然后调用重载过的service方法。以后在子类中就可以覆盖重写的service方法而不用进行向下转型操作了。
      HttpServlet类中定义的重载service方法的语法格式及处理代码:
        protected void service(HttpServletRequest req,HttpServletResponse resp)
  throws ServletException,java.io.IOException
        {
                ……
                req.HttpServletRequest中定义的方法();
                res.HttpServletResponse中定义的方法();
                ……
        }
      HttpServlet类中实现的重写的service方法的语法格式及处理代码:
        public void service(ServletRequest?req,ServletResponse?res)
                throws ServletException,java.io.IOException
        {
                HttpServletRequest?request = (HttpServletRequest)req;
                HttpServletResponse?response = (HttpServletResponse)res;
                service(request,response);//这里调用的是那个重载的service方法
        }
    最后要补充的就是如何编写一个简单的自动编译工具,分为两步:
      1.将包含有Servlet API的jar文件加入到CLASSPATH环境变量的路径列表中。
      2.将编译生成的.class文件放置在Web应用程序的WEB-INF/classes目录中,并且要有与包名对应的子目录结构。
    实现例子:使用 compile.bat批处理文件
      set CLASSPATH=%TOMCAT_HOME%/common/lib/servlet.jar;%CLASSPATH%
      javac -d d:/myweb/WEB-INF/classes %1 pause

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值