我们需要用到servlet的时候,都是右键,新建一个servlet,但是有人注意到一个细节没有,当我们手动给我们的servlet添加一个构造函数时候,会出现什么状况呢?

1.尝试添加无参构造函数


直接上代码

public class Test extends HttpServlet {

    Test(String a){
        System.out.println("这是构造函数");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

好了,一个我们都熟悉的基本的servlet,它的名字叫做Test。

为了方便起见,我们重写接口Servlet中的init()函数,并配置这个Servlet预加载,更直观的帮助我们理解。

public class Test extends HttpServlet {
Test(){ System.out.println("这是构造函数"); }
@Override
public void init() throws ServletException { System.out.println("这是Init函数"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }

好了,关于预加载,简单说,就是服务器运行的的时候,就会实例化这个servlet并且走完init()函数,这样,我们只需开启服务器,不需要进行请求,就可以看出这个servlet'是否被正确实例化。

 

好了,测试开始,启动服务器。

实验结果:手动写的Test()构造函数没有被执行,init()函数也没被执行。浏览器访问此Servlet时,404错误。

实验结论:当我们手动一个无参Servlet构造函数时,服务器就不会创建我们请求的servlet实例,当然也不会走servlet的生命周期

2.尝试有参构造函数

public class Test extends HttpServlet {

    Test(String a){
        System.out.println("这是构造函数");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("这是Init函数");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

结果同无参构造函数一样:服务器不会创建servlet实例。

3.web.xml给出错误提示

手动添加Servlet构造函数出现的问题及猜想-LMLPHP

错误说,我们的servlet没有默认的构造函数。

我们现在证明了,手动写一个有参和无参构造函数后,服务器都不会创建这个实例,根据xml错误,我们保留默认无参构造函数,并重载一个有参构造函数

public class Test extends HttpServlet {

    Test(){}

    Test(String a){
        System.out.println("这是构造函数");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("这是Init函数");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

实验结果:构造函数仍无法输出任何内容,init()方法也不输出,说明servlet仍未被创建实例。

4.结果猜想:我们都知道,当我们请求servlet时候,服务器会根据servlet的servlet-class,反射创建servlet对象,并且会将一切参数传入到实例中(例如request,response,servletConfig等),

大致流程就是Class.from("我们的servlet-class").getDeclaredConstructor(上述说的参数类型...).newInstance(上述说的参数的值...)

因为,只有这样构造实例,才能把一些必要的数据(request,response,servletConfig),封装到实例里面。

况且,这个有参构造函数,第一句又调用了无参构造函数,也就是 this();

这样,通过有参构造函数将参数传递过来并保存,然后在无参构造函数中,进行初始化servlet,因此,当我们重写了无参构造,服务器就无法完成这些流程,因此,服务器直接做一个判断,如果你手动写了构造函数,直接让这个servlet无法初始化。

02-06 01:15