|
Contents
Following best practices can ensure that your application does not suffer from common development and design mistakes that could affect performance. This paper outlines effective methods to use during the development and deployment phases of an application to improve the application's performance. Some of these guidelines are applicable to Sun ONE Application Server, and others are applicable to programming in the Java programming language and to using the Java2 Platform, Enterprise Edition (J2EE platform) in general. Depending on the application and context, these strategies can be followed in different ways. 1. J2EE Architecture
Here, we describe the three main facets of the J2EE architecture: its tiered structure, its software, and its request-handling mechanism.
1.1. n-tier System
A typical J2EE application is composed of an n-tier system in which a client obtains processed information from a Web server or an application server. The servers in turn access the information from enterprise systems such as RDBMS or ERP, process them by using contained business logic, and deliver the processed information to the client in an appropriate format. These layers can be designated as client layer (Web browser or rich Java client), middle layer (Web servers and application servers), and the back-end layer or data layer (enterprise systems such as databases). Figure 1 illustrates such an n-tier application:
1.2 Sun ONE Application Server Software
The Sun ONE Application Server software resides in the middle layer and consists of the following components:
Sun ONE Application Server
Sun ONE Application Server is part of a multithread environment and supports an application model predicated on J2EE technology-based standards. Sun ONE Application Server provides a comprehensive set of system and application services that support the deployment and execution of highly scalable, reliable business applications. The following key features of the Sun ONE Application Server platform make it ideal for meeting business and technical requirements:
Sun ONE Web Server
Sun ONE Web Server receives and processes HTTP and HTTPS requests from a Web browser. In a system based on Sun ONE Application Server, Sun ONE Web Server receives requests from Web clients and routes them to Sun ONE Application Server for processing by means of the Web Connector, an NSAPI plug-in that resides on the Web server. The Web Connector exposes the Sun ONE Application Server functionality through the Web and helps balance and distribute user requests across different instances of Sun ONE Application Server. Sun ONE Web Server also enforces and performs user authentication through the use of Access Control Lists (ACLs). ACLs are maintained on the Enterprise Server, specifying the URLs that are deemed protected and those that are public. On the basis of the ACLs, Sun ONE Application Server prompts for authentication information, either through basic authentication or certificate-based authentication, and then authenticates the user by a lookup in the user database, which is stored in Sun ONE Directory Server. This authentication is done without the need for any custom programming. Once the user has been authenticated, Sun ONE Application Server processes the requests.
Sun ONE Directory Server
Sun ONE Directory Server, the Sun ONE software implementation of the Lightweight Directory Access Protocol (LDAP), is the central repository for user and group information and provides unified management of users, groups, and ACLs across the enterprise. All Sun ONE server products are tightly integrated with Sun ONE Directory Server, which also stores application server configuration data. A single Sun ONE Directory Server can support multiple instances of Sun ONE Application Server, so all administration data for Sun ONE Application Server installations can be centralized in one place. Since Sun ONE Directory Server is the core of the Sun ONE Server product suite, user information should be migrated into Sun ONE Directory Server, specifically the information related to authentication (user names, passwords, and public certificates). Sun ONE Directory Server exists in addition to the database. Although Sun ONE Directory Server is not a relational database and should not be used as such, it can store user profile and contact information. Developers should consider this capability in the application design and system architecture. 1.3 Sun ONE Application Server Request Flow
Requests to Sun ONE Application Server can come from two types or sources:
The result: An HTML page is sent back to the Web-based client through the Web server or is sent to the rich client through RMI over IIOP. Figure 2 illustrates the request flow inside Sun ONE Application Server:
Sun ONE Application Server consists of several internal servers, called engines or processes, which take part in the Sun ONE Application Server request flow:
These engines are multithreaded. More than one KJS or KCS process can be running at a given time, and developers can configure the number of required engines. Although the Sun ONE Application Server installation allows up to 32 Java technology-based servers and 32 C++ servers for each Sun ONE Application Server instance, it is advisable to have no more than two Java servers per CPU for performance reasons. 2. Best Practices for Application Development
Application design and development is the most important phase in the software engineering cycle. A good design can make an application run several times faster and make it far more scalable than a poorly designed application. Be careful to make your application flexible enough to adapt to future changes in design and to integrate with applications or components. A J2EE application consists of different types of components such as servlets, JSP pages, and components based on EJB architecture (beans), each of which has a different role. Servlets and JSP pages usually reside in the Web container handling the presentation and page logic, whereas beans interact with enterprise systems and process information in accordance with the business logic they contain. When an application scales, the complexity of it also increases as new design strategies are required. Scaling requires clustering of servers, load balancing, and sharing of resources, which in turn, create new issues. Here, we consider some of the application design best practices that can be adopted to make applications more scalable and flexible.
2.1. Design with Sun ONE Application Framework
Sun ONE Application Framework is a J2EE technology-based development framework meant for enterprise Web application development. It drives a page-centric approach to development and consists of features such as display fields, application events, and component hierarchies. It is based on widely accepted design patterns such as Model-View-Controller (MVC) and Service-to-Workers. The Sun ONE Application Framework is already in use in applications worldwide. Predicated on J2EE technology-based standards, the framework does not depend on application-server-specific features and so applications developed on it are portable. Figure 3 illustrates the framework.
2.2. Reuse J2EE Technology-Based Patterns
P>Design
patterns are a commonly used set of effective and time-tested
solutions to general design problems encountered during the software
engineering cycle. Here, we talk about patterns that fall into the
object-oriented world and, in particular, the J2EE technology
community. Since a J2EE application can be divided into different
tiers according to presentation, business logic, and integration with
back-end systems, the design patterns are discussed from the
standpoint of a tier-based approach.
Presentation Tier Patterns
Business Tier Patterns
Integration Tier Pattern
For more information on J2EE design patterns, refer to Core J2EE Patterns, Best Practices and Design Strategies by Deepak Alur, John Crupi, and Dan Malks. (See http://www.phptr.com/corej2eepatterns/.)
2.3. Use Servlets and JSP Pages
Servlets and JSP pages afford several areas in which to exercise best practices in J2EE application development. Here, we describe 11 such areas.
Model-View-Controller Approach
P>The
MVC approach, also known as the Model 2 architecture, implements the
classic MVC design pattern for the presentation and content layer of
a J2EE application. It involves both JSP pages and servlets, as
follows.
The advantage of the MVC approach is that it leads to a clear separation between presentation and content. The disadvantage is its complexity: each request is handled by a JSP page and a servlet. For simple applications, you can program the JSP page to process the entire request and respond to the client without delegating the request to the controller servlet.
Base Servlet
For any application, you can provide a base servlet that performs operations such as user authorization, logging, or request redirection. Other servlets can inherit from the base servlet and override the base methods.
Object Scope
An object in a servlet or JSP page can exist in different scopes: request, application, session, and page scope. It is a good practice to ensure that the scope of the object be as small as possible without affecting the functionality. By following this practice, you ensure that the object is free for garbage collection once it serves its purpose. Each type of scope and its usage is described in the following section. In the descriptions, a shopping-cart object is created in a servlet and placed in a certain scope. It is then accessed by a JSP page in which the access method varies according to the type of scope used.
ShoppingCart cart = new ShoppingCart();
HttpSession session = Httpsession.getSession(true);
session.setAttribute("cart", cart.getId());
8JSP:
<jsp:useBean id="cart" scope="session" class="Cart" />
Connection conn = new Connection();
getServletContext().setAttribute("connection",conn);
10JSP:
<jsp:useBean id="conn" scope="application" class="Connection" />
Invoice cart = new Invoice();
request.setAttribute("invoice", invoice);
<redirect to jsp>
12JSP:
Invoice cart = (Invoice) request.getAttribute("invoice");
pageContext.setAttribute("foo",Foo.class,PageContext.PAGE_SCOPE);
Session Invalidation
It is highly recommended that user sessions be invalidated explicitly by the application rather than the Web container ending the session after timeout. Instance Variable Usage
Servlets are typically executed in a multithreaded environment, and different users could be executing the same servlet code. A client should not state information in servlet or instance variables of a JSP page. Since multiple users could request processing by the same servlet, the use of instance variables for storing conversational state could lead to information related to one user being overwritten by that of another user. Store
user conversational information in These recommendations do not imply that there should be no servlet instance variables. You can use servlet instance variables as long as they act as read-only variables during the request processing operations or do not hold request- or user-specific data. Initialization Operations
To
avoid performance overheads, perform expensive operations such as
initialization of connections to a resource only once and thereafter
let all components use the results. The Synchronization and Thread-Safe Coding
Servlet containers manage a pool of threads to respond to user requests. The same piece of servlet code could be executed in a different thread context by the servlet container while responding to concurrent requests from different users. It is essential that the servlet code be thread-safe so that requests can be correctly processed. Avoid synchronized methods and blocks of code within a servlet because they drastically reduce the performance and scalability of the application they are part of. Synchronizing parts of code would lead to serializing the execution of user requests. To work around such scenarios, use servlets that implement the single-thread model. Use these servlets sparingly because the container could create multiple servlet instances, thereby incurring additional object creation overhead. Remember that you have no control over the instance that would be used to handle a particular user request. The number of instances to be created for the single-thread model is specified in the deployment descriptor under Number of Singles; the default value is 10. Code Optimization
The following simple coding techniques can significantly improve the performance of a servlet:
Servlet Reloading
Many application servers allow a servlet to be reloaded without restarting the server. This is a useful feature because you can view changes in the servlet code without restarting the server after every code change. You can also configure the reload time for the servlet. For example, setting the reload time for a servlet to 1 second results in the server reloading the servlet class every second. You can, and should, turn this feature off in a production environment to reduce overhead. Usage of JSP Pages
P>JSP
pages are excellent presentation-layer components. They should deal
with layout and presentation of data that would be sent back to a
user as response. JSP pages should not contain Java code that
performs business logic operations; rather, any Java code within a
JSP page should perform presentation-control operations. The bulk of
changes in an application (after the first-cut code freeze) are done
in the presentation layer. By having a clear separation between the
request handling, control flow, and user response presentation
operations, you can minimize and localize the impact of such changes.
This practice, coupled with the capability of Sun ONE Application
Server to dynamically detect and load changes to JSP pages, can help
reduce the deployment and testing period.
Developers
who use JSP technology should have a clear understanding of the
default value of the different JSP tags. For instance, JSP pages
create Custom Tag Libraries for JSP Pages
Custom tag libraries can help extend the functionality of JSP pages. They accomplish what would otherwise be achieved by use of Java code within JSP pages. Sun ONE Application Server provides custom tag libraries for performing RDBMS, LDAP, looping, and caching operations. Tag libraries provide consistency across the presentation layer pages. By using tag libraries, you can change the entire set of presentation pages without modifying each page individually. Tag libraries also eliminate excessive Java code from JSP pages and obviate the widely used practice of copying pieces of code from one page to another. You can customize and extend some Web page design tools to provide support for custom tag libraries, thereby easing the design of Web pages. 2.4. Exploit EJB Component Models
You can follow best practices for three components based on EJB architecture (beans): entity beans, stateful sessions beans, and stateless session beans.
Entity Bean Usage
Although
entity beans transparently provide persistence and transactional
services and are ideal for modeling business objects, they do come
with a performance overhead. Entity beans are ideal to use in a
transactional process. They are not ideal to use when performing
queries to retrieve business objects that satisfy a particular
criterion; instead, if no subsequent transactional operations are
envisaged, then use a simple JDBC query followed by creation or
population of simple beans. Another workaround is to use
Stateful Session Bean Usage
Use
a stateful bean to store data that corresponds to the user
conversational state. Sun ONE Application Server supports failover of
stateful session beans. You can decide at the time of packaging or
deploying whether the session bean needs to be marked for failover.
Unlike Since stateful session beans are private to a client, their demand on server resources increases as the number of users using an application rises. Stateful session beans remain in the container until they are either explicitly removed by the client or removed by the container when they time out. The container must also passivate inactive stateful session beans to secondary storage. If the client subsequently accesses the bean, the container is responsible for activating the bean. The passivation and activation processes also impose a performance overhead on the server. Applications should explicitly remove the beans when they are no longer required, to reduce the overhead on the container (by eliminating the passivation process).
Stateless Session Bean Usage
Use a stateless session bean to access data or to perform transactional operations. Because stateless session beans have no affinity with the clients, they afford high scalability since a small number of such beans (typically managed by the bean container in a stateless bean pool) can serve a large number of clients. When a request for a service provided by a stateless session bean is received, the container can dispatch the request to any bean instance in the pool. 2.5. Communicate through Java Message Service
Java Message Service is a Java API for accessing message-oriented middleware (MOM) systems. It allows Java clients to communicate with one other through asynchronous messaging whereby the message is carried through a MOM provider such as Sun ONE Message Queue for Java technology (see http://www.iplanet.com). For more information about Java Message Service, visit http://java.sun.com/jms. Following are some basic guidelines for improving performance: Optimize
connections: The connection object is used for sessions that
create message producers or consumers. Call the
Process
messages concurrently: Java
Message Service provides a facility for consuming messages
concurrently. You use this facility by creating a
QueueConnection.createConnectionConsumer(javax.jms.Queuejava.lang.String, javax.jms.ServerSessionPool, int);
TopicConnection.createConnectionConsumer(javax.jms.Topic,
javax.jms.ServerSessionPool, int);
Use
sessions in Java Message Service: You can use sessions to create
producers and consumers. Sessions can be a
queueConnection.createQueueSession(boolean transacted, int acknowledgement_mode); topicConnection.createQueueSession(boolean transacted, int acknowledgement_mode); In the first argument, The second argument refers to the acknowledgment mode, which is discarded if the session is transacted. The different acknowledgment modes are as follows:
Message Delivery Modes
Messages
delivered to the JMS technology server can be durable or persistent
(
Message-Driven Beans
A
message-driven bean (MDB) is a new type of EJB component model
introduced in the EJB 2.0 specification. It models stateless JMS
technology consumers. Like any other bean, an MDB has an instance
pool at runtime; each instance is a To write an MDB:
2.6. Follow General J2EE Technology Best Practices
You can follow best practices for other, more general, J2EE technology operations, as described in the following section.
Logging Operations
Applications
should make use of common logging service calls. This standard way of
performing logging can go a long way toward providing control and
flexibility. Avoid using A simple and effective way for performing logging is to have a boolean variable that can help turn on (or off) logging. All logging calls should be similar to the following:
if (LOG_ENABLED)
{
log( Log this message );
}
With the boolean variable to control logging, you can instruct the entire component to turn logging on or off simply by modifying the value of one variable. This approach is better than the following approach:
public void log(String message)
{
if (LOG_ENABLED)
{
System.out.println( Log this message );
}
}
If the preceding mechanism were used to control logging, it would result in the creation of string objects that contain the messages. You can reduce the object creation overhead by placing the boolean control logic at the point of the logging method invocation instead of within the logging method itself. The ideal way to use logging is to have multilevel logging support. In this case, each logging call also has an associated logging level. The logging call would specify whether the message being logged is a DEBUG, INFO, WARNING, or ERROR message. You can specify the minimum level for logging in the logging operation. You can change this level in the logging configuration file while migrating the application to the testing or production environment, so no code-level changes need to be carried out.
Thread Management
User-developed applications should neither create nor spawn threads. Developers usually spawn threads when a lengthy processing operation needs to be performed, and such an operation must not affect the response to user requests. J2EE containers manage their own pool of threads, thereby relieving you of the task of coding such system programming services. These thread pools optimally use server resources and thus make the application servers scalable as the number of user requests increase. Spawning threads within application code would imply that these threads would use and compete with the application server threads for critical server resources. Use asynchronous processing in cases in which a certain user request would spend an inordinate amount of time processing the request and you want an immediate response or feedback to be sent to the user. You can use Java Message Service to provide asynchronous processing of messages and requests. Sun ONE Application Server supports Java Message Server and provides enhanced services for connection and user management.
Object Distribution
In a typical production environment, an application might be deployed in a cluster configuration involving multiple servers. Each server might have several KJS engines running at any given time. For failover and high availability, the session information is distributed and shared among all the application servers in a cluster. Because the serialization and synchronization of session data imposes some overhead, you should minimize the information in the session. In a nondistributed application, it is normal practice to use static class variables. Static class variables are shared among all the instances of a particular class in a single Java virtual machine. In the case of a distributed environment in which more than one Java virtual machine is present in the same server or across a cluster, the value of the static field may not be the same in each Java virtual machine, so avoid using static fields. You can, however, use the static fields in a distributed application when they are declared final, because their value will not change.
Caching of Lookup Objects
Application
components obtain objects such as RDBMS
JDBC API Usage
Typically,
you place JDBC technology calls in a
Application Constants
Use a separate class or properties file to maintain application-wide, constant data. In the file, place properties such as default date format, default locale, application database lookup name, and the JNDI API lookup name for beans. In the J2EE platform, applications can also have initialization parameters; place their values in the deployment descriptors. Doing so makes it easy to migrate code from one environment to another because such properties can be changed during the deployment process without the need to modify code.
Connection Management
Sun ONE
Application Server provides connection pooling for data sources.
Connection management service is provided for Sun ONE
software-supplied drivers as well as for registered third-party
drivers. In your applications, use registered data sources to obtain
connections. Avoid using the conventional mechanism of invoking
methods on the Obtain
a connection for application components only when they need to
perform a resource-related operation, and place the
Database Calls
To
improve performance of database queries, use If
the complete SQL statement is generated on the fly, then the database
server considers each such statement as a unique statement. The
reason is that even though the
SQL Queries
Almost all enterprises use information systems such as relational databases or enterprise legacy systems, and displaying or reporting data queried from such systems is a common activity. At times, the amount of data returned from queries can be huge. Such queries can also lead to intensive computing operations being performed in the database server. Another common problem faced by application developers is displaying query data in response pages. Since only a limited number of query results can be shown in a particular response, either applications need to store or cache the query results so that they can be used for subsequent requests or the queries need to be executed again. Keep the size of results from online queries low to ensure that server resources can be better used for other purposes. Queries that typically return large amounts of data should be processed by offline reporting tools. While
performing JDBC technology queries, applications should use
SQL Updates and Deletes
It is good programming practice to check the number of rows affected when a database update or delete operation is performed. When updating or deleting based on the primary key, be sure to check the number of rows affected to ensure that only one row was affected. Update and delete may not return errors when no rows are affected. The program should handle this case appropriately. 2.7. Observe Java Technology Best Practices
You can also follow best practices for I/O, object serialization, and class-loading operations in the Java programming language.
I/O Operations
Any
application in the Java programming language performs an I/O
operation, whether it is for serializing objects, getting input from
the user, or writing raw data to an output. I/O operations, if not
performed correctly, can slow down an application's performance
significantly. One of the main reasons for performance degradation
can be failure to buffer a read or write operation. Storage media
such as hard disks are inefficient when it comes to reading or
writing small pieces of data. By default, most of the I/O streams in
Java technology process one byte of data at a time. To increase the
performance, always buffer the input or output stream with a filter
stream class such as
Object Serialization
Objects
are serialized to be stored in files or to be sent over a network.
Distributed technologies such as RMI depend on object serialization.
You make objects serializable by implementing the
Class Loading
A large application comprises hundreds of classes. Having too many classes loaded into the memory can have a significant impact on the program's memory footprint. One of the problems frequently encountered is eager class loading, described in the next section. Whenever a compiler encounters a method, it tries before compiling to load all the classes the method references. For a factory method, all the classes it references will be loaded into memory. For example:
public Car getCar(String carType)
{
if(carType.equals("Sedan"))
return new Sedan;
else if (carType.equals("Convertible"))
return new Convertible;
else
return null;
}
Compiling
the previous method results in loading both the
public Object getCar(String carType)
{
if(carType.equals("Sedan"))
return Class.forName("Sedan").newInstance();
else if (carType.equals("Convertible"))
return Class.forName("Convertible").newInstance();
else
return null;
}
3. References
Books
World Wide Web
| |||||||||||||||||||||||||||||||||||
|
| ||||||||||||