- 浏览: 69266 次
- 性别:
- 来自: 成都
-
最新评论
-
qiaohhgz:
public static void String chang ...
一图和几句话解决java参数传值问题 -
ocaicai:
虽然我看懂了你的意思,但是我依然觉得表达得有些欠妥!
一图和几句话解决java参数传值问题 -
ql0722:
特别赞同第二条第三条
如果我再年轻几岁 -
zzc_zj:
很好的知识点,学习了
数据库查询select原理 -
dai03070609:
[url][/url][flash=200,200][/fla ...
数据库查询select原理
第二章: A Simple Servlet Container
Servlet容器(container)可以处理简单的servlets和静态资源。你可以使用PrimitiveServlet来测试这个容器。
为了知道application程序怎么工作的,你需要对javax.servlet.Servlet这个接口有更多的了解。这个接口将在后面讨论。之后,你将学习一个servlet容器为HTTP请求服务必须做些什么事。
The javax.servlet.Servlet Interface
Servlet编程:通过javax.servlet类和javax.servlet.http接口这两个包实现的。当然在这些类和接口中,javax.servlet.Servlet接口显得格外重要。所有的servlet必须(implements)实现这个接口或扩展(extends)这个类。
Servlet接口有5个方法,下面列出:
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()
Servlet的5个方法。Init、service和destroy方法是servlet的生命周期的方法。当servlet类实例化后,servlet容器就会调用init方法。servlet容器只准确地调用这个方法一次,表明这个servlet已经被放入服务中了。在servlet可以接收到任何之前,必须正确地完成init方法。一个servlet程序员可以重写(override)这个方法,写入只需要运行一次的初始化代码:载数据库驱动,初始化变量等等。在其他情况下,这个方法通常是空的方法。
servlet容器在当一个servlet有一个请求时就调用这个servlet的service方法。servlet容器会传递一个javax.servlet.ServletRequest对象和一个javax. servlet.ServletResponse对象。ServletRequest对象包含客户端的HTTP请求信息,而ServletResponse对象封装了servlet的响应。service方法在servlet的生命周期中会被调用很多次。
servlet容器从服务中移除一个servlet实例之前会调用destroy方法。当servlet容器关闭或者servlet容器需要释放掉一些内存时正常发生。这个方法只有在servlet的service方法里的所有的线程(exit)退出或者超时一段时间的情况下调用。当servlet容器调用了destroy方法后,它不会再调用该servlet的service方法。destroy方法给了servlet一个机会来清理所有的资源:内存、持有文件、线程等,以确保所有的持久化状态与servlet在内存的当前状态同步。
PrimitiveServlet是一个非常简单的servlet,它可以用来测试这章的servlet容器applications。PrimitiveServlet类实现了javax. servlet. Servlet并提供了Servlet的5种方法的实现。PrimitiveServlet是多么的简单。每次init,service或者destroy方法被调用,servlet把方法的名字打印到控制台上。此外,service方法获得了来自ServletResponse对象的java.io.PrintWtiter对象,这样就可以发送字符串到浏览器。
Application 1
现在让我们从servlet容器的角度来测试一下servlet程序。简而言之,一个功能齐全的servlet容器为每个对应的servlet的HTTP请求做了一下工作:
当servlet是第一次调用的时候,加载servlet类和调用init方法(仅调用一次)。
每次请求,构建一个javax. servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。
调用servlet的service方法,传递ServletRequest和ServletReponse对象。
当servlet类被关闭的时候,调用servlet的destroy方法和卸载servlet类。
这章的第一个servlet容器并不具备很全的功能。所以它仅仅只能运行非常简单的servlet。其功能如下:
等待HTTP请求。
构建ServletRequest对象和ServletResponse对象。
如果请求的是静态资源,调用StaticResourceProcessor实例的process方法,传递ServletRequest对象和ServletResponse对象。
如果请求的是一个servlet,就加载这个servlet类,调用它的service方法,传递ServletRequest对象和ServletResponse对象。
在这个servlet容器中,每次servlet被请求时该servlet就会被加载。
这个应用中包括下面6个类:
HttpServer1
Request
Response
StaticResourceProcessor
ServletProcessor1
Constants
这个应用程序的入口(静态main方法)是在HttpServer1这个类中。主方法创建一个HttpServer1的实例和调用它的await方法。await方法是用来等待HTTP请求,为每一个请求创建Request对象和Response对象。await方法还可以根据请求的是一个静态资源或者是一个servlet来把请求转发给StaticResourceProcessor实例或者ServletProcessor实例。
Constants类中包括了被其他类引用的static final WEB_ROOT。WEB_ROOT表明了PrimitiveServlet和静态资源所处可以被这个容器所能访问的路径目录。HttpServer1实例在它接收到shutdown命令在前一直处于等待HTTP请求的状态。
The HttpServer1 Class
请求一个servlet,你可以使用下面的URL:
http://machineName:port/servlet/servletClass
这样你可以使用浏览器调用本地的PrimitiveServlet:
http://localhost:8080/servlet/PrimitiveServlet
servlet容器可以装载PrimitiveServlet。但是,如果你再调用其他的servlet,在个servlet容器就会抛出一个异常。就是说这个版本的容器只能处理一个servlet。
The Request Class
Request类代表了一个请求对象,它被用来传给servlet的service方法。它必须诗选javax.servlet.ServletRequest接口。这个类必须为这个接口的所有方法提供实现。但是,一般情况下,我们只想做一个非常简单的实现。为了能够编译Request类,只需要为这些方法提供空的实现。下面可以看见所有的返回都为null。
The Response Class
Response类实现javax.servlet.ServletReponse接口。跟Request类似,除了getWriter方法外,其他的实现方法都为空。
在getWriter方法中PrintWriter类的构造函数的第二个参数是一个boolean类型,它表明是否自动刷新。如果是true,会自动刷新output。
此外,如果调用print方法恰巧发生在servlet的service方法的最后一行,output不会被发送到浏览器上。这个问题会在后面的应用被修正。
The StaticResourceProcessor Class
StaticResourceProcessor类是用来为请求静态资源提供服务的。它只有一个process方法。
process方法接收2个参数:Request实例和Response实例。这个方法简单调用Response对象的sendStaticResource方法。
The ServletProcessor1 Class
ServlerProcessor类是为servlet处理HTTP请求。
ServletProcessor1类出奇的简单,之包含了一个方法:process。这个方法接收2个参数:一个javax.servlet.ServletRequest的实例和javax.servlet.SetvletResponse的实例。ServletRequest方法中通过getRequestUri方法获取URI。
String uri = request.getUri();
记住URI是下面的格式:
/servlet/servletName
servletName是这个servlet类的名字。
为了加载这个servlet类,我们需要从URI中知道servlet的名字。我们可以使用下面的方法:
String servletName = uri.subString(uri.lastIndexOf("/")+1);
之后,process方法会加载这个servlet。为了达到加载servlet的目的,你需要创建一个类加载器(class loader),告诉这个类加载器这个想要被加载的类的路径。对于servlet容器。类加载器是直接搜索Constants.WEB_ROOT所指向的目录。这个目录是指向工作目录下的webroot目录。
为了加载servlet,你使用java.net.URLClassLoader类,它是java.lang.ClassLoader的间接子类。一旦你创建好了URLClassLoader的实例,你就可以用它的loadClass方法加载这个servlet类。初始化URLClassLoader是很明确的。这个类有3个构造函数,最简单的一个:
public URLClassLoader(URL[] urls);
urls是一个java.net.URL对象数组。每一个URL都是以一个/结束。确保指向一个目录。此外,这URL如果需要,可以引用一个JAR文件,这个JAR 文件会被下载下来并打开。
注意:在一个servlet容器中,一个类加载器可以找到servlet类的地方被称为仓库(repository)。
在我们的应用中,这里只有一个location是类加载器必须查看的。工作目录下的webroot目录。此外,我们通过创建一个单独URL的数组。这个URL类提供了构造函数的数量,这样就可以有很多种方式创建URL对象。在这个应用中,我们使用相同的构造函数:
public URL(URL context, java.lang.String spec, URLStreamHandler hander) throws MalformedURLException
你可以使用这个构造函数:通过传一个字符串说明给第二个参数,而第一个和第三个参数都为null。这里还有另外一个接收3个参数的构造函数:
public URL(java.lang.String protocol, java.lang.String host, java.lang.String file) throws MalformedURLException
如果你只是简单是使用下面的代码,编译器不知道你调用的是哪个构造函数:
new URL(null, aString, null);
你可以像下面使用:
URLStreamHandler streamHandler = null;
new URL(null, aString, streamHandler);
对第二个参数,你可以传一个包含仓库(repository)的字符串(一个servlet类可以被找到的目录)。向下面使用;
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
把所有的都结合起来,这里process方法创建URLClassLoader实例:
// create a URLClassLoader
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
有个类加载器,你可以使用loadClass方法加载一个servlet:
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
} catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
接下来,process方法创建一个被加载的servlet实例,向下转型为javax.servlet.Servlet,然后调用servlet的service方法:
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());
}
编译后运行这个应用:
http://localhost:8080/index.html或http://localhost:8080/servlet/PrimitiveServlet
当调用PrimitiveServlet,你可以看到浏览器上面的内容:
Hello.Roses are red.
你不能看到第二个字符串:Violets are blue,因为只有第一个字符串被刷新到浏览器。在第三章,我们将修正这个问题。
Servlet容器(container)可以处理简单的servlets和静态资源。你可以使用PrimitiveServlet来测试这个容器。
Listing 2.1: PrimitiveServlet.java import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter; public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ServletException { System.out.println("init"); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("from service"); PrintWriter out = response.getWriter(); out.println("Hello. Roses are red."); out.print("Violets are blue."); } public void destroy() { System.out.println("destroy"); } public String getServletInfo() { return null; } public ServletConfig getServletConfig() { return null; } }
为了知道application程序怎么工作的,你需要对javax.servlet.Servlet这个接口有更多的了解。这个接口将在后面讨论。之后,你将学习一个servlet容器为HTTP请求服务必须做些什么事。
The javax.servlet.Servlet Interface
Servlet编程:通过javax.servlet类和javax.servlet.http接口这两个包实现的。当然在这些类和接口中,javax.servlet.Servlet接口显得格外重要。所有的servlet必须(implements)实现这个接口或扩展(extends)这个类。
Servlet接口有5个方法,下面列出:
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()
Servlet的5个方法。Init、service和destroy方法是servlet的生命周期的方法。当servlet类实例化后,servlet容器就会调用init方法。servlet容器只准确地调用这个方法一次,表明这个servlet已经被放入服务中了。在servlet可以接收到任何之前,必须正确地完成init方法。一个servlet程序员可以重写(override)这个方法,写入只需要运行一次的初始化代码:载数据库驱动,初始化变量等等。在其他情况下,这个方法通常是空的方法。
servlet容器在当一个servlet有一个请求时就调用这个servlet的service方法。servlet容器会传递一个javax.servlet.ServletRequest对象和一个javax. servlet.ServletResponse对象。ServletRequest对象包含客户端的HTTP请求信息,而ServletResponse对象封装了servlet的响应。service方法在servlet的生命周期中会被调用很多次。
servlet容器从服务中移除一个servlet实例之前会调用destroy方法。当servlet容器关闭或者servlet容器需要释放掉一些内存时正常发生。这个方法只有在servlet的service方法里的所有的线程(exit)退出或者超时一段时间的情况下调用。当servlet容器调用了destroy方法后,它不会再调用该servlet的service方法。destroy方法给了servlet一个机会来清理所有的资源:内存、持有文件、线程等,以确保所有的持久化状态与servlet在内存的当前状态同步。
PrimitiveServlet是一个非常简单的servlet,它可以用来测试这章的servlet容器applications。PrimitiveServlet类实现了javax. servlet. Servlet并提供了Servlet的5种方法的实现。PrimitiveServlet是多么的简单。每次init,service或者destroy方法被调用,servlet把方法的名字打印到控制台上。此外,service方法获得了来自ServletResponse对象的java.io.PrintWtiter对象,这样就可以发送字符串到浏览器。
Application 1
现在让我们从servlet容器的角度来测试一下servlet程序。简而言之,一个功能齐全的servlet容器为每个对应的servlet的HTTP请求做了一下工作:
当servlet是第一次调用的时候,加载servlet类和调用init方法(仅调用一次)。
每次请求,构建一个javax. servlet.ServletRequest实例和一个javax.servlet.ServletResponse实例。
调用servlet的service方法,传递ServletRequest和ServletReponse对象。
当servlet类被关闭的时候,调用servlet的destroy方法和卸载servlet类。
这章的第一个servlet容器并不具备很全的功能。所以它仅仅只能运行非常简单的servlet。其功能如下:
等待HTTP请求。
构建ServletRequest对象和ServletResponse对象。
如果请求的是静态资源,调用StaticResourceProcessor实例的process方法,传递ServletRequest对象和ServletResponse对象。
如果请求的是一个servlet,就加载这个servlet类,调用它的service方法,传递ServletRequest对象和ServletResponse对象。
在这个servlet容器中,每次servlet被请求时该servlet就会被加载。
这个应用中包括下面6个类:
HttpServer1
Request
Response
StaticResourceProcessor
ServletProcessor1
Constants
这个应用程序的入口(静态main方法)是在HttpServer1这个类中。主方法创建一个HttpServer1的实例和调用它的await方法。await方法是用来等待HTTP请求,为每一个请求创建Request对象和Response对象。await方法还可以根据请求的是一个静态资源或者是一个servlet来把请求转发给StaticResourceProcessor实例或者ServletProcessor实例。
Constants类中包括了被其他类引用的static final WEB_ROOT。WEB_ROOT表明了PrimitiveServlet和静态资源所处可以被这个容器所能访问的路径目录。HttpServer1实例在它接收到shutdown命令在前一直处于等待HTTP请求的状态。
The HttpServer1 Class
请求一个servlet,你可以使用下面的URL:
http://machineName:port/servlet/servletClass
这样你可以使用浏览器调用本地的PrimitiveServlet:
http://localhost:8080/servlet/PrimitiveServlet
servlet容器可以装载PrimitiveServlet。但是,如果你再调用其他的servlet,在个servlet容器就会抛出一个异常。就是说这个版本的容器只能处理一个servlet。
Listing 2.2: The HttpServer1 Class's await method package ex02.pyrmont; import java.net.Socket; import java.net.ServerSocket; import java.net.InetAddress; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; public class HttpServer1 { /** WEB_ROOT is the directory where our HTML and other files reside. * For this package, WEB_ROOT is the "webroot" directory under the * working directory. * The working directory is the location in the file system * from where the java command was invoked. */ // shutdown command private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; // the shutdown command received private boolean shutdown = false; public static void main(String[] args) { HttpServer1 server = new HttpServer1(); server.await(); } public void await() { ServerSocket serverSocket = null; int port = 8080; try { serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // Loop waiting for a request while (!shutdown) { Socket socket = null; InputStream input = null; OutputStream output = null; try { socket = serverSocket.accept(); input = socket.getInputstream(); output = socket.getOutputStream(); // create Request object and parse Request request = new Request(input); request.parse(); // create Response object Response response = new Response(output); response.setRequest(request); // check if this is a request for a servlet or // a static resource // a request for a servlet begins with "/servlet/" if (request.getUri().startsWith("/servlet/")) { ServletProcessor1 processor = new ServletProcessor1(); processor.process(request, response); } else { StaticResoureProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // Close the socket socket.close(); //check if the previous URI is a shutdown command shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } }
The Request Class
Request类代表了一个请求对象,它被用来传给servlet的service方法。它必须诗选javax.servlet.ServletRequest接口。这个类必须为这个接口的所有方法提供实现。但是,一般情况下,我们只想做一个非常简单的实现。为了能够编译Request类,只需要为这些方法提供空的实现。下面可以看见所有的返回都为null。
Listing 2.3: The Request class package ex02.pyrmont; import java.io.InputStream; import java.io.IOException; import java.io.BufferedReader; import java.io.UnsupportedEncodingException; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; public class Request implements ServletRequest { private InputStream input; private String uri; public Request(InputStream input){ this.input = input; } public String getUri() { return uri; } private String parseUri(String requestString) { int index1, index2; index1 = requestString.indexOf(' '); if (index1 != -1) { index2 = requestString.indexOf(' ', index1 + 1); if (index2 > index1) return requestString.substring(index1 + 1, index2); } return null; } public void parse() { // Read a set of characters from the socket StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = input.read(buffer); } catch (IOException e) { e.printStackTrace(); i = -1; } for (int j=0; j<i; j++) { request.append((char) buffer(j)); } System.out.print(request.toString()); uri = parseUri(request.toString()); } /* implementation of ServletRequest */ public Object getAttribute(String attribute) { return null; } public Enumeration getAttributeNames() { return null; } public String getRealPath(String path) { return null; } public RequestDispatcher getRequestDispatcher(String path) { return null; } public boolean isSecure() { return false; } public String getCharacterEncoding() { return null; } public int getContentLength() { return 0; } public String getContentType() { return null; } public ServletInputStream getInputStream() throws IOException { return null; } public Locale getLocale() { return null; } public Enumeration getLocales() { return null; } public String getParameter(String name) { return null; } public Map getParameterMap() { return null; } public Enumeration getParameterNames() { return null; } public String[] getParameterValues(String parameter) { return null; } public String getProtocol() { return null; } public BufferedReader getReader() throws IOException { return null; } public String getRemoteAddr() { return null; } public String getRemoteHost() { return null; } public String getScheme() { return null; } public String getServerName() { return null; } public int getServerPort() { return 0; } public void removeAttribute(String attribute) { } public void setAttribute(String key, Object value) { } public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException{ } }
The Response Class
Response类实现javax.servlet.ServletReponse接口。跟Request类似,除了getWriter方法外,其他的实现方法都为空。
Listing 2.4: The Response class package ex02.pyrmont; import java.io.OutputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.File; import java.io.PrintWriter; import java.util.Locale; import javax.servlet.ServletResponse; import javax.servlet.ServletOutputStream; public class Response implements ServletResponse { private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; PrintWriter writer; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } /* This method is used to serve static pages */ public void sendStaticResource() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputstream fis = null; try { /* request.getUri has been replaced by request.getRequestURI */ File file = new File(Constants.WEB_ROOT, request.getUri()); fis = new FileInputstream(file); /* HTTP Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ] Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch!=-1) { output.write(bytes, 0, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } } catch (FileNotFoundException e) { String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; output.write(errorMessage.getBytes()); } finally { if (fis!=null) fis.close(); } } /** implementation of ServletResponse */ public void flushBuffer() throws IOException (){} public int getBufferSize() { return 0; } public String getCharacterEncoding() { return null; } public Locale getLocale() { return null; } public ServletOutputStream getOutputStream() throws IOException { return null; } public PrintWriter getWriter() throws IOException { // autoflush is true, println() will flush, // but print() will not. writer = new PrintWriter(output, true); return writer; } public boolean isCommitted() { return false; } public void reset() { } public void resetBuffer() { } public void setBufferSize(int size) { } public void setContentLength(int length) { } public void setContentType(String type) { } public void setLocale(Locale locale) { } }
在getWriter方法中PrintWriter类的构造函数的第二个参数是一个boolean类型,它表明是否自动刷新。如果是true,会自动刷新output。
此外,如果调用print方法恰巧发生在servlet的service方法的最后一行,output不会被发送到浏览器上。这个问题会在后面的应用被修正。
The StaticResourceProcessor Class
StaticResourceProcessor类是用来为请求静态资源提供服务的。它只有一个process方法。
Listing 2.5: The StaticResourceProcessor class package ex02.pyrmont; import java.io.IOException; public class StaticResourceProcessor { public void process(Request request, Response response) { try { response.sendStaticResource(); } catch (IOException e) { e.printStackTrace(); } } }
process方法接收2个参数:Request实例和Response实例。这个方法简单调用Response对象的sendStaticResource方法。
The ServletProcessor1 Class
ServlerProcessor类是为servlet处理HTTP请求。
Listing 2.6: The ServletProcessor1 class package ex02.pyrmont; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandler; import java.io.File; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class ServletProcessor1 { 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. 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()); } } }
ServletProcessor1类出奇的简单,之包含了一个方法:process。这个方法接收2个参数:一个javax.servlet.ServletRequest的实例和javax.servlet.SetvletResponse的实例。ServletRequest方法中通过getRequestUri方法获取URI。
String uri = request.getUri();
记住URI是下面的格式:
/servlet/servletName
servletName是这个servlet类的名字。
为了加载这个servlet类,我们需要从URI中知道servlet的名字。我们可以使用下面的方法:
String servletName = uri.subString(uri.lastIndexOf("/")+1);
之后,process方法会加载这个servlet。为了达到加载servlet的目的,你需要创建一个类加载器(class loader),告诉这个类加载器这个想要被加载的类的路径。对于servlet容器。类加载器是直接搜索Constants.WEB_ROOT所指向的目录。这个目录是指向工作目录下的webroot目录。
为了加载servlet,你使用java.net.URLClassLoader类,它是java.lang.ClassLoader的间接子类。一旦你创建好了URLClassLoader的实例,你就可以用它的loadClass方法加载这个servlet类。初始化URLClassLoader是很明确的。这个类有3个构造函数,最简单的一个:
public URLClassLoader(URL[] urls);
urls是一个java.net.URL对象数组。每一个URL都是以一个/结束。确保指向一个目录。此外,这URL如果需要,可以引用一个JAR文件,这个JAR 文件会被下载下来并打开。
注意:在一个servlet容器中,一个类加载器可以找到servlet类的地方被称为仓库(repository)。
在我们的应用中,这里只有一个location是类加载器必须查看的。工作目录下的webroot目录。此外,我们通过创建一个单独URL的数组。这个URL类提供了构造函数的数量,这样就可以有很多种方式创建URL对象。在这个应用中,我们使用相同的构造函数:
public URL(URL context, java.lang.String spec, URLStreamHandler hander) throws MalformedURLException
你可以使用这个构造函数:通过传一个字符串说明给第二个参数,而第一个和第三个参数都为null。这里还有另外一个接收3个参数的构造函数:
public URL(java.lang.String protocol, java.lang.String host, java.lang.String file) throws MalformedURLException
如果你只是简单是使用下面的代码,编译器不知道你调用的是哪个构造函数:
new URL(null, aString, null);
你可以像下面使用:
URLStreamHandler streamHandler = null;
new URL(null, aString, streamHandler);
对第二个参数,你可以传一个包含仓库(repository)的字符串(一个servlet类可以被找到的目录)。向下面使用;
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
把所有的都结合起来,这里process方法创建URLClassLoader实例:
// create a URLClassLoader
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
有个类加载器,你可以使用loadClass方法加载一个servlet:
Class myClass = null;
try {
myClass = loader.loadClass(servletName);
} catch (ClassNotFoundException e) {
System.out.println(e.toString());
}
接下来,process方法创建一个被加载的servlet实例,向下转型为javax.servlet.Servlet,然后调用servlet的service方法:
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());
}
编译后运行这个应用:
http://localhost:8080/index.html或http://localhost:8080/servlet/PrimitiveServlet
当调用PrimitiveServlet,你可以看到浏览器上面的内容:
Hello.Roses are red.
你不能看到第二个字符串:Violets are blue,因为只有第一个字符串被刷新到浏览器。在第三章,我们将修正这个问题。
评论
2 楼
langyu
2010-11-03
兄台如果把代码放到code标签中,学习起来就更容易了
1 楼
elgs
2010-11-03
这本书是非常值得珍藏的一本书,中国根本买不到,我在amazon上买到一本二手的。
发表评论
-
程序员的乐趣
2012-09-21 15:39 282近来闲的蛋痛,又因为公司里面有日志系统,每天必须写工作日志,少 ... -
2012考研失利 重拾JAVA 准备面试找工作
2012-02-26 23:07 813去年6月辞职考研 今年计算机统考408考起来蛋疼,挂在专业课上 ... -
弱弱的问一下 冰神是谁???
2011-05-10 17:19 18弱弱的问一下 冰神是谁??? -
程序员 爬友 考研
2011-04-26 10:36 409等待我的小球球入住 -
如果我再年轻几岁
2011-02-21 10:22 1170如果我再年轻几岁~(转 ... -
百度 、Google.hk 与 Google.com
2010-12-22 15:24 623今天搜索,发现了了百度、google.hk和google.co ... -
google map v3 GIS功能总结
2010-12-16 11:04 3409在CRM系统中嵌入了地图功能。只要是显示选择客户地 ... -
coder 爱翻译 How Tomcat Works 第二章 第二部分
2010-11-03 21:55 965Application 2 在第一个应用中,有一个严重的问题 ... -
飞车党 come on
2010-11-02 12:31 382哎,昏昏沉沉的我,今天居然会在上班路上被飞车小毛贼给掏包了。 ... -
coder 爱翻译 How Tomcat Works 第一章
2010-10-31 21:02 1393第一章 一个简单的web server 这章分析java we ... -
ExtJs 21种皮肤打包下载
2010-10-13 13:40 1713直接上rar包 -
我想大声告诉你
2010-10-12 23:27 333夜深了 我还为你不能睡 黎明前的心情 最深的灰 左右为难的你 ... -
json-lib 入门
2010-10-12 13:16 10221)JSON简介 2)JSON/LIST转换 3)JSON/M ... -
B/S结构浏览器兼容问题(一)获知是何种浏览器
2010-10-11 20:37 1309var Sys = {}; var ua = navigat ... -
祝福老一辈
2010-10-04 22:46 892以前的老莫看上去一脸严肃的表情,如今看来是一脸的慈祥。 老莫问 ... -
工作月总结
2010-09-14 15:36 902从找到工作到现在已经一个月时间了 公司很小,研发人员就2个。是 ... -
再看马士兵
2010-09-10 08:26 1028昨晚再次翻出一年半以前下的马士兵的网络部分的视频。 发现以前很 ... -
生日快乐
2010-09-08 12:36 239简简单单 生日快乐
相关推荐
适合读者 1.jsp/servlet 开发人员,想了解 tomcat 内部机制的 coder; 2.想加入 tomcat 开发团队的 coder; 3.web 开发人员,但对软件开发很有兴趣的 coder; 4.想要对 tomcat 进行定制的 coder。
Bad Programming Practices 101 Become a Better Coder by Learning How (Not) to Program 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书
基于 DeepSeek-Coder 实现翻译功能的 Python 源码。将待翻译的文本和翻译提示组合成输入文本,输入到模型中,模型会尝试进行翻译。最后打印出原文和翻译结果。
PHPCoder是一款专为PHP开发者设计的高效代码编辑器,旨在提供一个轻量级且功能丰富的开发平台。这款软件以其便捷性、易用性和强大的功能深受程序员喜爱。在本篇文章中,我们将深入探讨PHPCoder的各项特性、安装过程...
mediacoder 5685专业版,无普通版的限制
综上所述,Simulink HDL Coder 作为一款先进的工具,极大地简化了从算法设计到 FPGA 实现的整个过程,是现代电子设计自动化领域不可或缺的一部分。通过掌握其使用方法和技术要点,工程师们能够更高效地完成复杂的 ...
6. 插件扩展:MediaCoder有一个开放的插件架构,用户可以通过安装第三方插件来增加新的编码解码器、滤镜和其他功能,扩展其应用范围。 7. 用户友好:MediaCoder的界面简洁直观,即便是对编码不熟悉的用户也能快速...
PLC 编码器代码生成技术 PLC 编码器代码生成技术是指使用 Simulink PLC Coder 将 Simulink 模型、State...Simulink PLC Coder 是一种功能强大且灵活的代码生成工具,可以满足工业控制系统的需求,提高开发效率和质量。
Embedded Coder用于产生嵌入式处理器、目标快速原型板和大规模生产中使用的微处理器的可读的、紧凑的、快速的C和C++代码。Embedded Coder支持附加的MATLAB Coder™和Simulink Coder™配置选项,以及对生成代码的功能...
Mediacoder是一款强大的多媒体编码工具,专为音频和视频转换而设计,支持多种格式,如MP4、AVI、MKV等。本教程将深入讲解如何利用Mediacoder进行视频压制,优化视频质量,同时合理权衡码率与视频大小的关系。 **1. ...
Martin, "The Clean Coder: A Code of Conduct for Professional Programmers" Prentice Hall | 2011 | ISBN: 0137081073 | 256 pages | PDF | 6 MB Programmers who endure and succeed amidst swirling ...
虽然CoolCoder能够自动化大部分工作,但开发者依然可以自定义模板,对生成的代码进行微调,以满足特定项目的需求。这种灵活性确保了生成的代码既高效又符合项目风格。 6. **提高开发效率**: 使用CoolCoder,...
MediaCoder是一款功能强大的多媒体转换工具,它支持广泛的音频和视频编码格式,使用户能够轻松地在不同设备之间转换媒体文件。这款软件适用于个人用户、专业音频和视频制作人员,以及那些希望在各种设备上享受多媒体...
### HDL-Coder详细教程知识点概述 #### 一、生成HDL代码前的准备工作 在开始从Simulink模型生成HDL代码之前,需要完成一系列的准备工作,确保模型能够顺利生成高质量的代码。 ##### 1.1 使用`hdlsetup`进行模型...
PHPCoder用于快速开发和调试PHP应用程序,它很容易扩展和定制,完全能够符合开发者的个性要求.PHPCoder是一个非常实用的,功能强大的编程环境,而且它是免费的!
用于ARM内核,stm32嵌入式Matlab代码生成所需硬件支持包,包含Embedded Coder Interface to QEMU Emulator 版本 23.2.0、Embedded Coder Support ...压缩包共1.8G,故分成三个包,这是第一个,其他两个在主页都免费。
### MATLAB Coder 基本函数教程 #### MATLAB Coder 概述 MATLAB Coder 是一款能够将 MATLAB 代码转换成独立的 C 或 C++ 代码的强大工具。这一过程对于那些希望在非 MATLAB 环境下部署 MATLAB 代码的应用开发者来说...
接下来,我们讨论"magicalcoder文件去域名"的第二个方面——软件授权限制的解除。通常,商业软件会设定一定的授权机制,包括使用期限、设备数量或特定的使用环境(如特定域名)。这些限制是为了保护知识产权,防止...
texasinstrumentsc2000.mlpkginstall 支持TI的C2000系列工具包,要求MATLAB R2017a及其以上版本。 安装方法:打开matlab,调整路径到mlpkginstall文件所在目录;在current folder窗口里双击mlpkginstall文件即可开始...
MediaCoder行业版一款针对VOD及KTV视频点播行业开发的,用于转换和处理带有多音轨内容的视频节目的软件。它具备业界领先的视频编码引擎,在高性能转码的同时保持高画质,并通过丰富的视频滤镜增强画面视觉效果。作为...