手動新增Servlet構造函數出現的問題及猜想
我們需要用到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無法初始化。