Java培训之GenericServlet类

1.GenericServlet原理分析

GenericServlet类是一个抽象类,并且是Servlet接口的实现类,HttpServlet类的父类,下面我们通过一张图来更直观的了解GenericServlet的类结构,如图1-1所示:

ServletConfig接口
Servlet接口

Java培训之GenericServlet类
图1-1 GenericServlet类结构
通过图1-1发现,GenericServlet类不仅实现了Servlet接口,还实现了ServletConfig接口。因此,在GenericServlet类中一定包含Servlet接口和ServletConfig接口的所有方法.。接下来,我们创建一个类来模拟GenericServlet的功能,详情请参考GenericServlet案例详解,下载源代码。
(1)创建应用Example11,新建一个类MyServlet,该类实现了Servlet接口,具体代码如例1-1所示:
例1-1 MyServlet.java
public class MyServlet implements Servlet {
    /*
     * 成员变量config
     * */
     private ServletConfig config;
     public void init(){}
    @Override
    public void destroy() {
       System.out.println("destroy run……");
    }
    /*
     *  返回config,该方法一定在init方法之后执行
     * */
    @Override
    public ServletConfig getServletConfig() {
       return config;
    }
    @Override
    public String getServletInfo() {
       return "MyServlet….";
    }
/*
 * init()方法是这些方法中,最先被调用的,在本类构造方法执行后执行.
 * */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        /*
         * 将服务器创建的servletConfig对象赋值给本类的成员变量config,方便在其他方法中使用
         * */
       this.config=servletConfig;
           init();
    }
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
           throws ServletException, IOException {
       System.out.println("service run ……");     
    }
    /*
     * 获得Servlet的初始化参数
     * */
    public String getInitParameter(String name){
       return this.config.getInitParameter(name);
    }
    /*
     * 获得ServletContext对象
     * */
    public ServletContext getServletContext(){
       return this.config.getServletContext();
    }
    public String getServletName(){
       return this.config.getServletName();
    }
}
由例1-1可知,当前的MyServlet类中不仅包含了Servlet接口的五个方法,还包含了以下方法:

  • public ServletConfig getServletContext()
  • public String getInitParameter(String name)
  • public String getServletName()

由于GenericServlet类实现了ServletConfig接口,那么必然重写了ServletConfig的方法,因此在MyServlet 类中也要定义了ServletConfig的相关方法,这些方法的实现都是通过成员变量config调用自身的方法来实现的。
另外MyServlet类中还有一个无参的init()方法,该方法不是生命周期方法,它会被生命周期方法init(ServletConfig)方法调用。 这样做的目的是为了方便继承MyServlet类的子类,完成自己所需要的初始化工作,而不用再定义一个ServletConfig类型的成员变量。
(2)再创建一个Servlet类,让该类继承MyServlet 类,具体代码如例1-2所示:
例1-2  SonServlet.java
public class SonServlet extends MyServlet{
    @Override
    public void init(ServletConfig config) {
       // TODO Auto-generated method stub
       System.out.println("i am sonservlet…….");
    }
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
           throws ServletException, IOException {
       String value=getInitParameter("name");
    }
}
由例1-2可知,在SonServlet中定义了本类的init(ServletConfig)方法,该方法会覆盖父类的init(ServletConfig)方法。那么第一次访问该Servlet时,服务器会调用子类的init()生命周期方法进行初始化,父类的init()生命周期方法没有被调用,那么父类的config成员就为null,当 SonServlet 类中的service方法调用父类的getInitParameter()方法时就会出现空指针异常。所以,SonServlet 类中不能覆写有参的init()方法,而应该覆写无参的init()方法。这也是为什么在MyServlet类中定义一个无参的init()方法,然后再在有参的init方法中调用无参的init方法的原因。
以上案例就是为了方便开发人员开发Servlet,以后就不用去实现Servlet接口。现在我们来看一下GenericServlet的源码,源码的jar包。具体代码如例1-3所示:
例1-3 GenericServlet.java
public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;
    public GenericServlet() {}
    @Override
    public void destroy() {}
    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }
    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }
    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    @Override
    public String getServletInfo() {
        return "";
    }
    @Override
    public void init (ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    public void init() throws ServletException {}
    public void log(String msg) {
        getServletContext().log(getServletName() + ": " + msg);
    }
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    @Override
    public String getServletName() {
        return config.getServletName();
    }
}
由例1-3可知,GenericServlet类的原理和我们刚才写的MyServlet 类的原理是一样的。继承GenericServlet 类比实现Servlet接口更加方便Servlet开发。





 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/253098.html

(0)
上一篇 2022年5月7日
下一篇 2022年5月7日

相关推荐

发表回复

登录后才能评论