Hi all,
This is a follow-up to the 'overhead of jsp include' question below:
http://stackoverflow.com/questions/1479218/jsp-performance-using-jspinclude
In our application, developers have 'modularized' jsp fragments by heavy use of "jsp:includes" for "common" jsp code repeated throughout the application.
Pros
The pro's are as follows:
it's DRY-- we define the jsp fragment once. This is a big help when you need to change some html and don't need to find/replace/search/destroy.
it's fairly easy to follow: you clearly pass in the parameters. When you edit the 'included' page, you 'know what you're getting', i.e. vs. some 'global variables' declared in the 'including/calling' page.
Cons
- performance overhead of the additional request
Questions
So as a follow-on:
- how much performance overhead does a 'jsp:include' incur? It's not obvious from the tomcat code (though you see it does a whole lot more than would an inline call). Also in profiling the app I've never requestDispatcher.include() or invoke() methods appears as hotspots.
- could someone point as to where precisely lies the bulk of the overhead? (i.e. method X in class Y) Or whether it's just all the "little stuff" (e.g. setting attributes or object creation and subsequent GC) that happens with each request?
- what are the alternatives? (AFAIK @include and jsp:include. anything else?)
- (Stupid bonus question) why couldn't the servlet engine 'include' the jsp at compile time, i.e like an 'inline macro with parameters' so that we developers could get the clarity of 'jsp:include' and the peformance of '@include'.
I've wondered about this last question for a while. I've used code generation tools in a past life and never quite understood the lack of options for including jsp fragments.
For the benefit of the reader I've included the tomcat 'applicationDispatcher.invoke()' method (tomcat 5.5. sorry if it's dated). For clarity, I've pruned the exception handling.
thanks in advance
will
private void invoke(ServletRequest request, ServletResponse response,
State state) throws IOException, ServletException {
// Checking to see if the context classloader is the current context
// classloader. If it's not, we're saving it, and setting the context
// classloader to the Context classloader
ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
ClassLoader contextClassLoader = context.getLoader().getClassLoader();
if (oldCCL != contextClassLoader) {
Thread.currentThread().setContextClassLoader(contextClassLoader);
} else {
oldCCL = null;
}
// Initialize local variables we may need
HttpServletResponse hresponse = (HttpServletResponse) response;
Servlet servlet = null;
IOException ioException = null;
ServletException servletException = null;
RuntimeException runtimeException = null;
boolean unavailable = false;
// Check for the servlet being marked unavailable
if (wrapper.isUnavailable()) {
wrapper.getLogger().warn(
sm.getString("applicationDispatcher.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE))
hresponse.setDateHeader("Retry-After", available);
hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm
.getString("applicationDispatcher.isUnavailable", wrapper
.getName()));
unavailable = true;
}
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
servlet = wrapper.allocate();
}
}
...exception handling here....
// Get the FilterChain Here
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain = factory.createFilterChain(request,
wrapper,servlet);
// Call the service() method for the allocated servlet instance
try {
String jspFile = wrapper.getJspFile();
if (jspFile != null)
request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
request.removeAttribute(Globals.JSP_FILE_ATTR);
support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT,
servlet, request, response);
// for includes/forwards
if ((servlet != null) && (filterChain != null)) {
filterChain.doFilter(request, response);
}
// Servlet Service Method is called by the FilterChain
request.removeAttribute(Globals.JSP_FILE_ATTR);
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
}
...exception handling here....
// Release the filter chain (if any) for this request
try {
if (filterChain != null)
filterChain.release();
}
...exception handling here....
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
}
...exception handling here....
// Reset the old context class loader
if (oldCCL != null)
Thread.currentThread().setContextClassLoader(oldCCL);
// Unwrap request/response if needed
// See Bugzilla 30949
unwrapRequest(state);
unwrapResponse(state);
// Rethrow an exception if one was thrown by the invoked servlet
if (ioException != null)
throw ioException;
if (servletException != null)
throw servletException;
if (runtimeException != null)
throw runtimeException;
}