Optimizing servlets
This section provides specific
techniques for improving code for the servlet components of your web
application. When looking to refactor a web application, you should also
consider using design patterns. For more information on design patterns, see Chapter 2, "Design Patterns".
Caching static data in the
init method
Where possible, you should try to
cache static data rather than have your web application dynamically generate it
each time a client makes a request. With servlets, you can cache the static data
in the init method.
If the servlet is registered in the
web.xml file and the load-on-startup element is set to 1, JRun
invokes the init method when the server starts up. Otherwise, JRun
invokes the init method the first time (and only the first time) a
client requests the servlet.
The following example shows a
servlet's init method that gets initialization parameters from the
application's web.xml file and builds a footer that is later used in the
servlet's doGet method.
You can invoke the
init method with or without passing in a ServletConfig object.
However, in this case, you invoke it with the ServletConfig so you can access
the initialization parameters to build the footer. public class InitOverride extends HttpServlet {
String name;
String email;
String copyright;
String footer;
public void init (ServletConfig config) throws ServletException {
super.init(config);
name = config.getInitParameter("name");
email = config.getInitParameter("email");
copyright = config.getInitParameter("copyright");
footer = ("<HR><FONT FACE="arial,helvetica,sans-serif" SIZE=-2>Copyright "
+ copyright + ". Brought to you by: <A HREF="mailto:" + email + "">" + name + "</A></FONT>");
}
public void doGet ( HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/html");
...
out.println(footer);
out.println( "</body></html>" );
}
}
The following lines show the
servlet definition in the web.xml file, including the initialization parameters:
<servlet>
<servlet-name>InitOverride</servlet-name>
<servlet-class>InitOverride</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>Nick Danger</param-value>
</init-param>
<init-param>
<param-name>email</param-name>
<param-value>ndanger@sandstonebuilding.com</param-value>
</init-param>
<init-param>
<param-name>copyright</param-name>
<param-value>2000, 2001, 2002</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Caching static data in the
ServletContext object
The ServletContext object stores
objects as attributes. By caching objects, such as hashtables or other
structures, you reduce the processing load of your application because all
servlets in the application access the same context. Furthermore, if you store
the object into the context in the servlet's init method, the
method only runs once.
Use the init method of
your servlet to build an object, store it in the ServletContext, and then access
the object in the body of the servlet with a call to
ServletContext.getAttribute . For database tables, you cannot store
a ResultSet object as an attribute; you must refactor the data as an array or
some other object.
In the servlet's init
method, the following example iterates over a ResultSet and stores a Hashtable
in the ServletContext using the context's setAttribute method. In
the doGet method, the servlet accesses the Hashtable object through
the ServletContext and uses a request parameter to get the appropriate row for
output. public void init () throws ServletException {
...
ResultSet rs = stmt.executeQuery(sqlstmt);
Hashtable h = new Hashtable();
while (rs.next()) {
h.put(rs.getString("ABBR"),rs.getString("LONGNAME"));
}
getServletContext().setAttribute("statelist", h);
...
}
public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
Hashtable h = (Hashtable) getServletContext(). getAttribute("statelist");
String state = (String) h.get(request.getParameter("state"));
out.println(request.getParameter("state") + " is an abbreviation for " + state);
...
}
When working with JSPs, use the
application object, as that is the implicitly declared ServletContext object in
a JSP.
Using the print method instead
of println
When sending data to the
PrintWriter object, use the print method instead of the
println method, as shown in the following example: PrintWriter out = response.getWriter();
//out.println("This is the inefficient output");
out.print("This is the efficient output");
In Java, the print
method is a more efficient output method than println . Internally,
println takes the input and sends it to print . The
difference between using println and print is that
println inserts a newline character at the end of the string.
However, this does not change the way the output is rendered by the client
browser unless the client views the source of the HTML.
Using the HttpSession object
for state management
For state management, use the
HttpSession object instead of hidden fields, cookies and URL rewriting. When
using the HttpSession API, JRun passes only the session ID between the client
and server, not the session data itself. This is also easier to use than the
other methods because the implementation details are hidden by the session
object's API.
For JSP developers, use the
implicit session object.
For more information on using the
HttpSession object for state management, see "Working with sessions".
Flushing output
Periodically flush data so that the
client sees something before the entire page finishes loading. While this does
not improve the overall responsiveness of your application, it appears to your
user that the page has been processed more quickly.
This technique works well if you
have graphics-heavy or processing-intensive sections of a page that might be
slow to download.
For example: PrintWriter out = response.getWriter();
out.print(header);
out.flush(); //flush the header
...
out.print("/images/large_graphic.gif");
out.flush(); //flush a large graphic in the body
...
out.print(footer);
out.flush(); //flush the footer
Use this technique for JSP pages
with the implicit out object.
Increasing the response
object's buffer
Servlets load content in the
response object's buffer. When the buffer is full, the servlet creates a socket
connection to the client and flushes the buffer. To reduce the number of sockets
and network traffic, you can increase the size of the buffer.
The response buffer for a servlet
defaults to 4kb. JRun flushes the buffer whenever the response size reaches this
size. Set the buffer to a larger value to decrease the number of flushes
necessary by using the setBufferSize method as shown in the
following example: response.setBufferSize(8192);
To check the size of the buffer,
use the getBufferSize method, as shown in the following example:
out.print("Buffer size is " + response.getBufferSize());
Increasing the PrintWriter
object's buffer
If you increase the buffer size of
the PrintWriter, then JRun flushes the response data less frequently. This
results in fewer sockets being opened and fewer connections being made.
Use a ByteArrayOutputStream object
to increase the buffer size of the PrintWriter, as shown in the following
example: ...
response.setContentType("text/html");
ByteArrayOutputStream bos = new ByteArrayOutputStream(8192);
PrintWriter out = new PrintWriter(bos, true);
out.print("<html><head><title>Using BytaArrayOutputStream</title></head>");
out.print("<body>");
...
out.print( "</body></html>" );
response.setContentLength(bos.size());
bos.writeTo(response.getOutputStream());
...
Restricting calls to
ServletContext.log
Calls to the ServletContext.log
method can degrade performance. Limit calls to this method and use calls to
System.out.println when possible.
* iWiz´Ô¿¡ ÀÇÇؼ °Ô½Ã¹° À̵¿µÇ¾ú½À´Ï´Ù (2010-02-03 16:57)
|