我們到底能走多遠系列(9)
扯淡:
最近晚上在看魅力記錄的《玄奘之路》,可以瞭解些曆史,理解些文化,比其它的節目好多了,推薦各位欣賞。
上周讀書,有兩個故事:
第一個:
有一個養雞場幾千隻雞分別排列的被關在狹小的雞籠裡,雞籠的前面有傳送帶為小雞送來食物,後面有傳送帶送走產下的雞蛋。可是卻注意到有幾十隻小雞在外面“逍遙”,還有飼養員在給他們餵食。
於是就問:是否需要幫忙吧這些雞趕到籠子裡去呢?
飼養員回答說:哦,這些雞是在外面養著的。要是籠子裡的那些雞看不到有的雞自由自在的生活,它們就會失去信心,不下蛋。沒有這些放養的雞,其它的就會放棄一切,然後死去。
突然驚異的發現我們的生活和這些雞是何等的相似,有多少人生活在籠子裡,看著外面的世界裡別人在探險,在實現自己的夢想,自由自在的生活,然後繼續省會在自己的籠子裡。
作者描述自己起先放棄一年的時間,去到外面的世界看看,最後放棄了自己的職業,成為了逍遙自在的那一個。
第二個故事我放到本文的最後告訴各位哦,哈哈。
主題:
在前面的主題中我們已經瞭解過servlet的工作流程:Servlet-我們到底能走多遠系列(7)
問題1:tomcat什麼時候載入servlet?
有兩種情況
一種是啟動時載入
一種是請求時載入
第一種是在web.xml中的<servlet>節點下增加類似:<load-on-startup>1</load-on-startup>的節點
例子如下:
<servlet> <servlet-name>DicDataIniter</servlet-name> <servlet-class>com.init.DicDataIniter</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DicDataIniter</servlet-name> <url-pattern>/DicDataIniter</url-pattern> </servlet-mapping>
關於load-on-startup,需要瞭解的是:
1)load-on-startup元素標記容器是否在啟動的時候就載入這個servlet(執行個體化並調用其init()方法)。2)它的值必須是一個整數,表示servlet應該被載入的順序2)當值為0或者大於0時,表示容器在應用啟動時就載入並初始化這個servlet;3)當值小於0或者沒有指定時,則表示容器在該servlet被選擇時才會去載入。4)正數的值越小,該servlet的優先順序越高,應用啟動時就越先載入。5)當值相同時,容器就會自己選擇順序來載入。所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是優先順序
第二種的流程類似如:
問題2:tomcat是怎麼載入一個servlet類的呢?
根據上篇對一個簡單的webServer類比(How Tomcat Works 學習-我們到底能走多遠系列(8)),在到達“載入servlet類,執行個體化一個servlet執行個體”這一步之前的工作我們已經完成了。我們已經取得了來自http訊息中的uri,也就已經取得了需要調用的servlet的名字。
根據《How tomcat works》,先搞一個自己的servlet:沒什麼邏輯,只是產生class檔案放到指定的檔案夾下等待載入。
package code.tomcat.servletContainer;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.*;public class PrimitiveServlet implements Servlet{ public void init(ServletConfig config) throws ServletException { System.out.print("init"); } public ServletConfig getServletConfig() { return null; } // 一旦實現了service方法那麼就不會就不會調用父類的service方法從而調用doGet或doPost public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.print("service"); PrintWriter writer = res.getWriter(); writer.println("Hello. Roses are red."); } public String getServletInfo() { return null; } public void destroy() { System.out.print("destroy"); }}
載入方法如下:
package code.tomcat.servletContainer;import java.io.File;import java.io.IOException;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.net.URLStreamHandler;import javax.servlet.Servlet;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class ServletProcessor1 { public void process(Request request, Response response){ // 取得request處理好的uri String uri = request.getUri(); // servlet 類名 String servletName = uri.substring(uri.indexOf("/") + 1); // 類載入器,利用提供的url目錄來載入class檔案,大多數情況下我們的程式在jvm啟動的已經有類載入器載入我們需要的類檔案。 // 但是最為需要及時部署的伺服器-servlet容器,需要自己去載入放到伺服器的工程 URLClassLoader loader = null; // URLClassLoader建構函式需要URL數組,這裡是需要載入一個類 URL[] urls = new URL[1]; // 構造URL用,雖然是null,但如果直接在URL中直接用null來代替,編譯器不答應啊 URLStreamHandler streamHandler = null; File classPath = new File("/webroot"); try { // servlet檔案夾位置 String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamHandler); // 得到傳說中的類載入器 loader = new URLClassLoader(urls); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // .class檔案載入後就是java中的Class類執行個體啦 Class myClass = null; try { // servlet Class類執行個體 myClass = loader.loadClass(servletName); } catch (ClassNotFoundException e) { e.printStackTrace(); } Servlet servlet = null; try { // 用newInstance方法得到一個servlet執行個體 servlet = (Servlet)myClass.newInstance(); // 調用PrimitiveServlet的service方法 servlet.service((ServletRequest)request, (ServletResponse)response); } catch (Exception e) { System.out.println(e.toString()); } }}
如此,servlet流程中的初始載入這一步就可以勉強完成了,tomcat中的實現要複雜很多吧,原理基本是差不多了,先打下基礎。
關於類載入:
其實tomcat啟動的時候就有大量的類載入工作需要做,應為tomcat本身就是個java工程嘛。
------------
System.getProperty:
有個類似寫日誌的方法:
/** * 寫日誌 * @param logString * @throws IOException */ public void writeLog(String logString) throws IOException { File logFile = new File("d:\\我的文件\\test.log"); // 寫 FileWriter writer = new FileWriter(logFile,true); // 取得斷行符號符號 String nextLine = System.getProperty("line.separator"); writer.write(logString + nextLine); writer.flush(); writer.close(); }
其中System.getProperty("line.separator")方法,值得熟悉。
我們可以通過這樣的方式取得一些System層級的常量。
java.version Java 運行時環境版本java.vendor Java 運行時環境供應商java.vendor.url Java 供應商的 URLjava.home Java 安裝目錄java.vm.specification.version JAVA 虛擬機器規範版本java.vm.specification.vendor JAVA 虛擬機器規範供應商java.vm.specification.name JAVA 虛擬機器正式名稱java.vm.version JAVA 虛擬機器實現版本java.vm.vendor JAVA 虛擬機器實現供應商java.vm.name JAVA 虛擬機器實現名稱java.specification.version Java 運行時環境規範版本java.specification.vendor Java 運行時環境規範供應商java.specification.name Java 運行時環境正式名稱java.class.version Java 類格式版本號碼java.class.path Java 類路徑java.library.path 載入庫時搜尋的路徑列表java.io.tmpdir 預設的臨時檔案路徑java.compiler 要使用的 JIT 編譯器的名稱java.ext.dirs 一個或多個擴充目錄的路徑os.name 作業系統的名稱os.arch 作業系統的架構os.version 作業系統的版本file.separator 檔案分隔字元(在 UNIX 系統中是”/”)path.separator 路徑分隔字元(在 UNIX 系統中是”:”)line.separator 行分隔字元(在 UNIX 系統中是”/n”)user.name 使用者的賬戶名稱user.home 使用者的主目錄user.dir 使用者的當前工作目錄
好吧,來講一下第二個故事吧:
一個印第安人和他的朋友走到美國繁華的街道上,汽車的鳴笛聲,警笛聲,人們的喊聲,整個街道雜訊簡直震耳欲聾。
突然一個印第安人說:我聽到有個蟋蟀在叫。
他的朋友說:什嗎?你瘋了嗎?在這麼吵的地方,你怎麼可能聽到蟋蟀的叫聲呢?
可是那個印第安人卻非常肯定,他走到街對面的一塊水泥石板前,上面長滿了灌木。他在灌木堆裡找,就在那裡找到了一隻蟋蟀。
他的朋友問:太不可思議了,你是怎麼做到的?
印第安人說:沒有什麼不可思議的,著取決於什麼對你是真正重要的。來我來告訴你怎麼回事。
他拿出一塊硬幣,扔到行人路上,他們發現幾乎所有在行人路上的人都低頭去查看地上的硬幣是不是他們遺落的。
你明白了嗎?這一切取決於什麼對你來說是最重要的。
讓我們繼續前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不會成功。
共勉