As we've seen, servlets offer a powerful mechanism for integrating Web servers and enterprise-wide business components. Now let's look at some of the best practices that are adopted in enterprise applications that involve servlets as one of the layers.
Leverage the MVC pattern
Use servlets as controllers, as described in the MVC pattern. Presentation is typically done using a JSP and the servlet is left to invoke the business component and pass on the necessary data for the presentation layer.
Use of SingleThreadModel
SingleThreadModel servlets should be avoided because most of the servlet container implementations have a huge system overhead. Instead use thread synchronization when necessary.
Use HttpSessions
By design, servlets are meant to be stateless component and they use external objects such as HttpSession to maintain state information for a user conversation. Application servers serialize inactive sessions and store them on disk because these objects take a lot of memory and the server has to share the allocated memory efficiently for other resources such as EJBs and JMS resources. Sessions are normally released from memory using the invalidate() function or when they time out. So, users have to take care of implementing one of these to make sure that sessions are released when the client is done with the conversation. Also, keep the session object lean and store valuable data in a database instead of storing it as part of session to prevent losing the data in unpredictable server crashes.
Use the Init() method
As explained, the init() method is invoked when the servlet instance is created. This is the most convenient method for performing some of the complex logic that must be performed once; for example, JDBC connection pool initialization, EJB home lookup, and so on. The init() method is also the best place to initialize the servlet instance variables because this method is threadsafe by default.
Synchronization in servlets
This should be avoided because large synchronization blocks make a servlet single threaded and thereby decreases the throughput drastically.
Optimization techniques in the service() method
Apart from minimizing the use of synchronization blocks, some of the following optimization techniques can be used as well: setting content-length variables for efficient flushing, using ServletOutputStream instead of PrintWriter, and using the print() method for println() and partial data flushing. Along with this, using StringBuffer for string concatenation improves performance. Using caching (when appropriate) and pre-generating large Web sites can help, too.
Using the destroy method
The destroy method should be used to free up resources such as database connections and initial contexts and to close sockets and files.
Modularity improvements
All complex logic (for example, EJBs) should be moved to a separate business layer to keep the logic in the servlet simple.
Shared resources
A servlet being multithreaded should take special care when modifying servlet instance variables because these are shared by multiple resources. Use synchronization and/or transactions.
Connection pooling
Try to avoid obtaining a connection to the database or a backend legacy application (such as a Tuxedo connection) for every request. Use connection pooling wherever possible and initialize using the init method. The developer should take care of releasing connections when the usage is over, such as in the destroy method of the servlet. The data source object used in every SQL access should be reused instead of looking up the javax.sql.DataSource object. Also in some application servers including WebLogic Server, connections such as JDBC connections can be initialized at server startup time. In those scenarios, it's better to use the server configuration feature to set up the connections rather than doing it through the init() method. For detailed information about WebLogic Serverbased JDBC connection pooling, refer to the chapter on JDBC.
Persistent connections
Avoid using flush() in the response because doing so closes the connection between WebLogic Server and the client. WebLogic Server is capable of using persistent connections between the client and the server. The connections are closed by an explicit flush() or a keepalive connection parameter in the server configuration file (config.xml).
Understanding the caching options (headers) and their efficient use improves the effectiveness of the servlet.
A session replication strategy (for example, in-memory or JDBC) should be carefully chosen based on a number of parameters, such as system performance criteria, database availability, and so on.
Session persistence should not used as a long-term shortage mechanism between long running client conversations because a session might not be alive when the client comes back. The application should instead take care of state persistence in such cases.
Sessions and cookies
Cookies are usually stored in the client browser for enabling features such as default field values, where the cookie lives in the client browser forever. Sessions should not be used as cookie wrappers and thereby attempt to store long-term client data in a session.
Automatic servlet reloading
Like most application servers, WebLogic Server provides an auto-reloading feature for servlets, which enables dynamic reloading of servlets at every configured interval to refresh the servlet content. It is a useful feature in development, but should be avoided in a production environment because it tends to degrade performance.