我们需要用到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没有默认的构造函数。
我们现在证明了,手动写一个有参和无参构造函数后,服务器都不会创建这个实例,根据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无法初始化。