servlet 詳解(二)-繼承體系
熟悉servlet,我們不只是要用到,還要徹底研究他的繼承體系,如果之前沒有認真學習他的生命周期和運行過程,那么繼承體系你也只能有個略懂。
我的做法,自己寫類來模擬 genericservlet和httpservlet2個類!並且理解他們為什么要這么做!
(一)模擬genericservlet
1,我們新建一個類,如MyGenericServlet,讓他實現Servlet、ServletConfig和Serializable
前2個類Servlet、ServletConfig,我們不需要詳述,前面我已經講過作用,Serializable這個接口是為了讓他能在網絡上傳輸。
2,實現他的一些基本方法,如下:
private ServletConfig config;//實現config參數
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public String getInitParameter(String param) {
// TODO Auto-generated method stub
return config.getInitParameter(param);
}
@Override
public Enumeration<String> getInitParameterNames() {
// TODO Auto-generated method stub
return config.getInitParameterNames();
}
@Override
public String getServletName() {
// TODO Auto-generated method stub
return null;
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return this.config;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
this.config=config;
init();
}
public void init() throws ServletException {
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("hello world");
}
public ServletContext getServletContext(){
return config.getServletContext();
}
我們說servlet的生命周期是首先運行帶有參的init方法,那么我們想要子類重寫並且保障config被傳入就一定要定義一個空參的方法,並且在有參方法中執行,這樣根據多態的特性,子類重寫父類init方法,被執行的是子類的方法,所以我們只需要在子類重寫空參方法,這樣保障config被傳入后再執行自己的方法,如果子類重寫有參方法,那么悲哀了,肯定報錯,就沒有ServerletConfig對象了!所以在這個類中的init方法是這么實現的!
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
this.config=config;
init();
}
public void init() throws ServletException {
}
然后講一下為什么要用getInitParameter(String param)這個方法,子類想要獲取config對象,如果沒有這個方法我們肯定是這么調用!
super.getServletConfig().getInitParameter("param");
從中看出,servlet為了優化一點點細節,從得多好,他用了一個getInitParameter(String param)方法,讓子類可以少寫一點點代碼.
super.getInitParameter("param");
而自身只多寫了這樣一個方法,所以我們父類的構造要合理設計!
public String getInitParameter(String param) {
// TODO Auto-generated method stub
return config.getInitParameter(param);
}
子類只需要這樣寫:
package gwd.com.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Server2 extends MygenericServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
System.out.println("這是我自定義的初始化");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
String code=getInitParam("code");
System.out.println(code);
}
}
(二)模擬HttpServlet
至於HttpServerlet這個類是為了http協議而生的,我們建一個MyHttpServlet類!他只處理http請求!而響應或請求我們都在service中實現!
我們再來看看上面這個類(Servlet2)中的service方法!
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
String code=getInitParam("code");
System.out.println(code);
}
我們看到他的參數名ServletRequest arg0, ServletResponse arg1!ServletRequest和ServletResponse只能用到普通請求,要實現http必須依靠HttpServletRequest和HttpServletResponse來實現,所以我們要把這兩個參數強轉,然后重載一個service方法單獨處理,當然為了代碼復用,我們這個MyHttpServlet必須繼承MyGenericServlet,代碼如下:
package gwd.com.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyHttpServlet extends MygenericServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
HttpServletRequest res=(HttpServletRequest) request;
HttpServletResponse resp=(HttpServletResponse)response;
service(res, resp);
}
private void service(HttpServletRequest res, HttpServletResponse res2) {
// TODO Auto-generated method stub
String method=res.getMethod();
//System.out.println(method);
if("GET".equals(method)){
doGet(res,res2);
}
else if("POST".equals(method)){
doPost(res,res2);
}
}
protected void doPost(HttpServletRequest res, HttpServletResponse res2) {
// TODO Auto-generated method stub
}
protected void doGet(HttpServletRequest res, HttpServletResponse res2) {
// TODO Auto-generated method stub
}
}
在重載的service中,我們可以判斷出請求的是什么方法,是get還是post,然后分離出來處理,給子類自由實現,這就是著名的模板方法設計模式!(后面我再單獨寫博!),注意了如果這2個方法寫成private的活,子類將無法重寫!
然后子類只要繼承並重寫dopost和doget方法就可以了,我們以后寫servlet也只需要繼承httpservlet方法,查看httpservlet和GeneticServerlet類的源碼,是不是和我的設計差不多呢?
子類我們可以這么寫,是不是越來越簡單了呢?
package gwd.com.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Sever1 extends MyHttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest req,HttpServletResponse resp){
System.out.println("doget");
}
protected void doPost(HttpServletRequest req,HttpServletResponse resp){
System.out.println("dopost");
}
}
(三)我們弄張圖來總結一下繼承體系!
時間急,請多指正!