Servlet知識詳解(一)ServletContext物件 和 ServletConfig物件學習筆記
@ 3 當請求URL為/abc/a.do,/abc/*和*.do都匹配,那個servlet響應 答:servlet引擎將呼叫Servlet1 @ 4 當請求URL為/a.do,/*和*.do都匹配,哪個servlet響應 答:servlet引擎將呼叫Servlet2 @ 5 當請求URL為/xxx/yyy/a.do,/*和*.do都匹配,哪個servlet響應 Servlet引擎將呼叫Servlet2【即:/*的優先順序高於 *.do】 3 Servlet例項物件的生命週期細節 Sevlet是一個供其他java程式(Servlet引擎如Tomcat伺服器程式)呼叫的Java類,它不能獨立執行,它的執行完全由Servlet引擎來控制盒排程。 針對客戶端的多次Servlet請求,通常情況下,伺服器只會建立一個Servlet例項物件,也就是說Servlet例項物件一旦建立,它就會駐留在記憶體中,為後續的其他請求服務,直至web容器退出,servlet例項物件才會銷燬。 在Servlet的整個生命週期內,Servlet的init方法只被呼叫一次。而對一個servlet的每次訪問請求都導致Servlet引擎呼叫一次一次servlet的service方法。對於每次訪問請求,Service引擎都會建立一個新的HttpServletRequest請求物件和一個新的HttpServletResponse響應物件,然後將這兩個物件作為引數傳遞給它呼叫的Servlet的service()方法,service方法再根據請求方式分別呼叫doXXX方法。
4:Servlet例項物件的預裝載配置<load-on-startup> 如果在<servlet>元素中配置了一個<load-on-startup>元素,那麼WEB應用程式在啟動時,就會裝載並建立Servlet的例項物件,以及呼叫Servlet例項物件的init()方法。 舉例: <servlet> <servlet-name>invoker</servlet-name> <servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> 用途舉例:為web應用寫一個initServlet,這個servlet配置為啟動時裝載,為整個web應用建立必要的資料庫表和資料。 5:web應用程式的預設Servlet 在<tomcat的安裝目錄>/conf/web.xml檔案中,註冊了一個名稱為org.apache.catalina.servlets.DefaultServlet的Servlet,並將這個Servlet設定為了預設Servlet 凡是在web.xml中找不到匹配的<servlet-mapping>元素的URL,他們的訪問請求都將交給預設Servlet處理,也就是說,預設Servlet用於處理所有其他Servlet都不處理的訪問請求。 例如:當訪問Tomcat伺服器伺服器中的某個靜態html檔案和圖片時,實際上是在訪問這個預設SErvlet.。 【備註:為避免遮蔽迷人的預設Servlet強大全面的功能,精良不要自定義預設servlet】 6:Servlet的執行緒安全問題 多執行緒安全的由來 當多個客戶端併發訪問同一個Servlet時,web伺服器會為每一個客戶端的訪問請求建立一個執行緒,並在這個執行緒上呼叫Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發執行緒安全問題。
SingleThreadMode介面 解決多執行緒安全問題 如果某個Servlet實現了SingleThreadMode介面,那麼Servlet引擎將以單執行緒模式來呼叫其service方法。 SingleThreadMode介面中沒有定義任何方法,只要在Servlet類的定義中增加實現SingleThreadMode介面的宣告即可。對於實現了SingleThreadMode介面的Servlet,Servlet引擎仍然支援對該Servlet的多執行緒併發訪問,其採用的方式是產生多個Servlet例項物件,併發的每個執行緒分別呼叫一個獨立的Servlet例項物件。 實現SingleThreadMode介面並不能真正解決Servlet的執行緒安全問題,因為Servlet引擎會建立多個Servlet例項物件,而真正意義上解決多執行緒安全問題是指一個SerVlet例項物件被多個執行緒同時呼叫的問題。事實上,在Servlet API 2.4中,已經將SingleThreadMode標記為Deprecated(過時的). 【備註1:多執行緒併發操作共享資料,就會發生執行緒安全問題。Synchronized程式碼塊可以很好的解決執行緒安全問題,但是會造成伺服器響應效能變得極差,很難提供大量的併發訪問服務,所以要慎用。共享資料包括如:成員變數,或是靜態成員變數等。】 【備註2:慎用靜態成員的增長問題,會同類位元組碼一同長期駐留在系統中,並將靜態變數中的資料長期駐留在記憶體中,最終會造成記憶體溢位。可在新增、使用之後,再找機會釋放掉。】 6:ServletConfig物件--獲取Servlet的初始化引數 在Servlet的配置檔案中,可以使用一個或多個<init-param>標籤為servlet配置一些初始化引數 當servlet配置了初始化引數後,web容器在建立servlet例項化物件時,會自動將這些初始化引數封裝到ServletConfig物件中,並在呼叫servlet的init方法時,將ServletConfig物件傳遞給servlet。進而,程式設計師通過ServletConfig物件就可以得到當前servlet的初始化引數資訊。 該物件的作用:a:獲得字符集編碼;b:獲得資料庫連線資訊;c:獲得配置檔案。 Demo範例: web.xml檔案的配置: <web-app> <servlet> <servlet-name>ServletDemo4</Servlet-name> <init-param><!--servletConfig--> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>xxx</param-name> <param-value>yyy</param-value> </init-param> </servlet></web-app> java原始檔中的編碼 //通過servletConfig獲取servlet配置的初始化引數 public class ServletDemo4 extends HttpServlet{ public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ ServletConfig config = this.getServletConfig(); //該類為我們書寫了通過init()方法獲取ServletConfig物件的程式碼,我們只需要呼叫this.getSErvletConfig();即可 //獲取初始化引數的方式1:獲取單個引數值 //String
第二部分 //配合servlet5,通過servletContext獲取5帶過來的資料 public class ServletDemo6 extends HttpServlet{ public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ ServletContext context = this.getServletContext(); System.out.println(context.getAttribute("data")); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ doGet(request,response); } } (2)獲取WEB應用的初始化引數 Demo樣例: 第一部分: <web-app> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/test</param-value> </context-param> <context-param> <param-name>username</param-name> <param-value>root</param-value> </context-param> <context-param> <param-name>password</param-name> <param-value>root</param-value> </context-param>L </web-app> 第二部分: 通過servletContext獲取web應用配置的初始化引數 public class ServletDemo7 extends HttpServlet{ public void doGet(HttpServletRequest,HttpServletResponse response) throws ServletException ,IOException{ //Stringvalue=this.ServletContext().getInitParameter("xxx"); String url = this.getServletContext().getInitParameter("url"); String username=this.getServletContext().getInitParameter("username'); String password = this.getServletContext().getInitParameter("password"); System.out.println(url); System.out.println(username); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ doGet(request,response); } } 獲取檔案MIME型別的值 Demo樣例 通過servletContext獲取檔案的mime型別 public class ServletDemo8 extends HttpServlet{ public void doGet(HttpServletRequest request ,HttpServletResponse response) throws ServletException,IOException{ String filename="1.jpg"; ServletContext context = this.getServletContext(); System.out.println(context.getMimeType(filename)); response.setHeader("content-type","image/jpeg"); } public void doPost(HttpServletResponse repuest,HttpServletResponse response) throws ServletException ,IOException{ doGet(request,response); } } (4) 實現Servlet請求的轉發 Demo樣例: //servletDemo9收到請求後,轉發給servletDemo1處理(mvc設計模式) public class ServletDemo9 extends HttpServlet{ public void doGet(HttpServletRequest request ,HttpServletResponse response) throws ServletException ,IOException{ String data ="aaaaaa"; this.getServletContext().setAttribute("data",data); RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/view.jsp"); rd.forward(request,response); //RequesteDispatcher rd= this.getServletContext().getRequestDispatcher("/servlet/ServletDemo10"); // rd.forward(request,response); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ doGet(request,response); } } 【備註:轉發servlet的路徑,是該servlet的對映路徑,而非其類名稱。所以若是更改了類名稱,則需要更改該servlet的web。xml檔案中註冊及對映程式碼】 9:利用ServletContext物件讀取資原始檔 通過ServletContext物件 實現讀取資原始檔的三種方式: demo樣例 //用servetContext讀取web工程不同位置的資原始檔 .properties檔案(屬性檔案) public class ServletDemo11 extends HttpServelt{ public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ //test5(); } //讀取配置檔案的第一種方式【注意:資源在WebRoot下面】 private void test1() throws IOException{ ServletContext context =this.getServletContext(); InputStream in = context.getResourceAsStream("db/properties"); Properties prop = new Properties();//map prop.load(in); String url=prop.getPropery("url"); System.out.println(url); } //讀取配置檔案的第二種方式【注意:資源在webroot下面】 private void test2()throws IOException{ ServletContext context = this.getServletContext(); String realpath=context.getRealPath("/db.properties"); //獲取到操作檔名 realpath=xxx.properties String filename = realpath.substring(realpath.lastIndexOf("\\")+1); System.out.println("當前讀到的檔案是:"+filename); FileInputSream in = new FileInputStream(realpath); Properties prop = new Properties(); prop.load(in); String url=pro.getProperty("ur"); } //讀取配置檔案的第三種方式【注意:資源在webRoot下面】 private void test3() throws IOException{ ServletContext context = this.getServletContext(); URL url = context.getResource("/resource/db.properties"); inputStream in = url.openStream(); Properties prop = new Properties(); prop.load(in); String url = prop.getProperty("url"); } //【注意:資源在src下面】 //讀取src下面的配置檔案(傳統方式不可取)。注:相對路徑是相對於java虛擬機器的相對位置,而在傳統方法中我們設定//classpath來設定與java虛擬機器讀取程式的路徑。而在javaweb中則不可行,但一切都可受到serviceContext的管理。 private void test4()throws IOException{ FileInputStream in = new FileInputStream("classes/db.properties")://此種方式不可行 } //讀取src下面的配置檔案【注意:資源在src下面】 private void test5() throws IOException{ InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); Properties prop = new Properties();//map prop.load(in); String url = prop.getProperty("url"); } public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{ doGet(request,response); } } 10 在web工程的普通java程式中如何讀取資原始檔 Demo樣例 public class StudenDao {//servlet public String get()throws IOException{//類裝載器讀 test1(); test2(); return null; } public void test2() throws IOException { ClassLoader loader StudentDao.class.getClassLoader(); Url url = loader.getResource("cn/itcat/dao.db.properties");//此時仍然把資源轉載進記憶體了。、 String filepath =url.getPath();//獲取其絕對路徑 FileInputStream in = new FileInputStream(filepath); Properties prop = new Properties();//map prop.load(in); String url = prop.getproperty("url"); }
//以下程式碼在讀檔案時,讀到不到更新後的資原始檔
public void test1() throws IOException{
ClassLoader loader = StudentDao.class.getClassLoader();
InputStream in = loader.getResourceAsStream("cn/itcast/dao/db.properties");
Properties prop = new Properties(); //map
prop.load(in);
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(url);
System.out.println(username);
System.out.println(password);
}
//通過類裝載器讀檔案時,需要注意的問題
//備註:當資原始檔很大時,採用類裝載器裝載時,可能會造成記憶體溢位。
}
【重點知識:Web工程中,使用“類裝載器”讀取相對路徑的資源。相對路徑是相對於類路徑classes資料夾/src路徑下。】
src類路徑下: servlet時:使用ServletContext物件獲取器絕對路徑,
非servlet時:使用類裝載器使用其相對路徑(相對於src)
WebRoot下: servlet時:使用ServletContext物件獲取器絕對路徑進行讀取。
非servlet時:無法讀取。
11、獲取web.xml檔案中配置的web應用的顯示名稱
Demo樣例:
//獲取web.xml檔案中配置的web應用的顯示名稱
web.xml中配置:<display-name>day05</display-name>
public class ServletDemo13 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = this.getServletContext().getServletContextName();
response.getWriter().write("<a href='/"+name+"/1.html'>點點</a>");
} //開發階段的工程名稱可能與釋出階段的工程名稱不相同,這樣做就免於更改路徑中的工程名稱。
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
}