Tomcat當中在接受到要調用的Servlet請求后,需要載入相應的Servlet類,然后創建Servlet類實例,從而調用Servlet類實例的service()方法
下面實例的場景,request和response分別是一個javax.servlet.ServletRequest實例和一個javax.servlet.ServletResponse實例,request通過getUri()方法從ServletRequest當中獲取uri
uri格式為/servlet/servletName
其中servletName就是所請求servlet資源的類名,針對這個資源名,調用URLClassLoader類載入相應的類實例
public void process(Request request, Response response) { String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); URLClassLoader loader = null; try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(Constants.WEB_ROOT); // the forming of repository is taken from the createClassLoader // method in // org.apache.catalina.startup.ClassLoaderFactory String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); // the code for forming the URL is taken from the addRepository // method in // org.apache.catalina.loader.StandardClassLoader class. urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString()); } Class myClass = null; try { myClass = loader.loadClass(servletName); } catch (ClassNotFoundException e) { System.out.println(e.toString()); } Servlet servlet = null; try { servlet = (Servlet) myClass.newInstance(); servlet.service((ServletRequest) request, (ServletResponse) response); } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } }
使用java.net.URLClassLoader類來完成,該類是java.lang.ClassLoader類的一個直接子類,一旦創建了URLClassLoader類的實例之后,就可以使用它的loadClass()方法來載入Servlet類,實例化URLClassLoader類有三種方法,也就是有三個構造方法
構造方法摘要 | |
---|---|
URLClassLoader(URL[] urls) 使用默認的委托父 ClassLoader 為指定的 URL 構造一個新 URLClassLoader。 |
|
URLClassLoader(URL[] urls, ClassLoader parent) 為給定的 URL 構造新 URLClassLoader。 |
|
URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) 為指定的 URL、父類加載器和 URLStreamHandlerFactory 創建新 URLClassLoader。 |
URLClassLoader 參數: urls - 從其位置加載類和資源的 URL 拋出: SecurityException - 如果安全管理器存在並且其 checkCreateClassLoader 方法不允許創建類加載器。 另請參見: SecurityManager.checkCreateClassLoader()
public URLClassLoader(URL[] urls)使用默認的委托父 ClassLoader 為指定的 URL 構造一個新 URLClassLoader。\n
首先在父類加載器中搜索 URL,然后按照為類和資源指定的順序搜索 URL。這里假定任何以 '/' 結束的 URL 都是指向目錄的。\n
如果不是以該字符結束,則認為該 URL 指向一個將根據需要下載和打開的 JAR 文件。
如果有安全管理器,該方法首先調用安全管理器的 checkCreateClassLoader 方法以確保允許創建類加載器。
參數中urls是一個java.net.URL 對象數組,當載入一個類時每個URL對象都指明了類載入器要到哪里查找類。
若一個URL以“/”結尾,則表明它指向的是個目錄,否則,URL默認指向一個JAR文件,根據需要載入器會下載並打開這個JAR文件。
在這個例子當中,類載入器只需要查找一個位置,即工作目錄下的webroot目錄,因此,需要先創建一個只有一個URL對象的數組。
URL類提供了一系列的構造函數,因此有很多方法可以創建URL對象。
URL public URL(URL context, String spec, URLStreamHandler handler) throws MalformedURLException通過在指定的上下文中用指定的處理程序對給定的 spec 進行解析來創建 URL。如果處理程序為 null,則使用兩參數構造方法進行解析。 參數: context - 要在其中解析規范的上下文。 spec - 將作為 URL 解析的 String。 handler - URL 的流處理程序。 拋出: MalformedURLException - 如果未指定任何協議,或者找到了未知協議。 SecurityException - 如果安全管理器存在並且其 checkPermission 方法不允許指定流處理程序。 另請參見: URL(java.lang.String, java.lang.String, int, java.lang.String), URLStreamHandler, URLStreamHandler.parseURL(java.net.URL, java.lang.String, int, int)
可以將第二個參數指定為一個目錄,指定第一個和第三個參數為null,這樣就可以使用構造函數了,但是我們看到在URL當中,還有一個構造函數,它也接受三個參數,
URL
public URL(String protocol,String host,String file) throws MalformedURLException
根據指定的 protocol 名稱、host 名稱和 file 名稱創建 URL。使用指定協議的默認端口。
此方法等同於調用帶四個參數的構造方法,四個參數為 protocol、host、-1 和 file。 此構造方法不執行對輸入的驗證。
參數:
protocol - 要使用的協議名稱。
host - 主機名稱。
file - 主機上的文件。
拋出:
MalformedURLException - 如果指定了未知協議。
另請參見:
URL(java.lang.String, java.lang.String, int, java.lang.String)
所以為了編譯器的區別,指明第三個參數的類型
URLStreamHandler streamHandler = null;
new URL(null,aString,streamHandler);
第二個參數中的字符串指明了倉庫的路徑,也就是查找servlet類的目錄。可以使用下面的代碼生成倉庫
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();