1. 程式人生 > >手動添加Servlet構造函數出現的問題及猜想

手動添加Servlet構造函數出現的問題及猜想

conf 重載 接口 傳遞 錯誤 右鍵 rom str 參數

我們需要用到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無法初始化。

手動添加Servlet構造函數出現的問題及猜想