Table of contents
Three: JSP compilation principle
One: Introduction to Jasper
For JSP
-
based
web
applications, we can directly
write Java code in
JSP pages
, add third-party tag libraries, and use EL expressions. But no matter what form of processing, the final output to the client is a standard HTML page (including js , css... ), and does not contain any java- related syntax. In other words, we can regard jsp as a script running on the server side. So how does the server convert the JSP page into an HTML page?
The Jasper module is Tomcat 's JSP core engine, we know that JSP is essentially a Servlet . Tomcat uses Jasper to analyze JSP syntax, generate Servlet and generate Class bytecode, when users access jsp , they will access Servlet , and finally respond directly to the browser with the access result. In addition, when running, Jasper will also detect whether the JSP file is modified, and if it is modified, it will recompile the JSP file.
Two: JSP compilation method
1. Runtime compilation
Tomcat
does not automatically compile
JSP files when starting a
web
application , but only compiles the JSP
files that need to be accessed when the client requests for the first time .
Create a
web
project
and
write
JSP
code
:
<%@ page import="java.text.DateFormat" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF‐8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
DateFormat dateFormat = new SimpleDateFormat("yyyy‐MM‐dd
HH:mm:ss");
String format = dateFormat.format(new Date());
%>
Hello , Java Server Page 。。。。
<br/>
<%= format %>
</body>
</html>
①: Compilation process
Tomcat
configures a org.apache.jasper.servlet.JspServlet
in the default
web.xml
to handle all requests ending in .jsp or .jspx . This Servlet implementation is the entry point for runtime compilation.
JspServlet processing flow chart:
2. Compilation results
1
) If the parameter
scratchdir is configured in
tomcat/conf/web.xml
, the result of jsp compilation will be stored in this directory.
2
) If this option is not configured, the compiled result will be stored in
work/Catalina(Engine name )/localhost(Host name )/Context name under the
Tomcat installation directory
. Suppose the project name is jsp_demo01.
3
) If you use the
IDEA
development tool to integrate
Tomcat
to access
the jsp in the
web project
, the compiled result is stored in:
C:\Users\Administrator\.IntelliJIdea2019.1\system\tomcat\_project_tomcat\w
ork\Catalina\localhost\jsp_demo_01_war_exploded\org\apache\jsp
②: Precompile
In addition to compiling at runtime, we can also
compile all the JSP pages in
the Web
application at one time directly when the Web application starts
.
In this case, during the running of the Web application, real-time translation is not necessary, but the Servlet corresponding to the JSP page is directly invoked to complete request processing, thereby improving system performance.
Tomcat
provides a
shell
program
JspC
to support
JSP
precompilation, and
provides a catalina-tasks.xml file in the
Tomcat installation directory
to declare the Ant tasks supported by Tomcat , so we can easily use Ant to execute JSP precompilation compile. (To use this method, you must ensure that Apache Ant has been downloaded and installed before ).
Three: JSP compilation principle
1. Code Analysis
Compiled
.class
bytecode file and source code
:
public final class index_jsp extends
org.apache.jasper.runtime.HttpJspBase
implements
org.apache.jasper.runtime.JspSourceDependent,org.apache.jasper.runtime.Js
pSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long>
_jspx_dependants;
static {
_jspx_dependants = new
java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("jar:file:/D:/DevelopProgramFile/apache‐tomcat‐
8.5.42‐windows‐x64/apache‐tomcat‐8.5.42/webapps/jsp_demo_01/WEB‐
INF/lib/standard.jar!/META‐INF/c.tld", Long.valueOf(1098682290000L));
_jspx_dependants.put("/WEB‐INF/lib/standard.jar",
Long.valueOf(1490343635913L));
}
private static final java.util.Set<java.lang.String>
_jspx_imports_packages;
private static final java.util.Set<java.lang.String>
_jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = new java.util.HashSet<>();
_jspx_imports_classes.add("java.util.Date");
_jspx_imports_classes.add("java.text.SimpleDateFormat");
_jspx_imports_classes.add("java.text.DateFormat");
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager
_jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory =
_jspxFactory.getJspApplicationContext(getServletConfig().getServletContex
t()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager =
org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getSe
rvletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest
request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) &&
!"HEAD".equals(_jspx_method) &&
!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType()))
{
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs
only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF‐8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>$Title$</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write(" ");
DateFormat dateFormat = new SimpleDateFormat("yyyy‐MM‐dd
HH:mm:ss");
String format = dateFormat.format(new Date());
out.write("\n");
out.write(" Hello , Java Server Page 。。。。\n");
out.write("\n");
out.write(" <br/>\n");
out.write("\n");
out.write(" ");
out.print( format );
out.write("\n");
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null)
_jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
From the compiled source code interpretation, the following points can be analyzed:
1
) Its class name is
index_jsp
, inherited from
org.apache.jasper.runtime.HttpJspBase
, which is a subclass of HttpServlet, so
jsp
is essentially a
Servlet
.
2
) The resources that the current
JSP page depends on are saved through the attribute
_jspx_dependants
, including the imported external JSP pages, imported tags, jar packages where the tags are located, etc., which are convenient for use in subsequent processing (such as recompilation detection, so it is in the form of a Map saves the last modification time of each resource).
3
) The
imported java package is stored through the attribute
_jspx_imports_packages
, and javax.servlet is imported by default ,
javax.servlet.http, javax.servlet.jsp
。
4
)
The imported classes are stored through the attribute
_jspx_imports_classes , and the DateFormat,
SimpleDateFormat and Date imported through the import command will be included in this collection. The _jspx_imports_packages and _jspx_imports_classes properties are mainly used to configure the EL engine context.
5
) The request processing is completed by the method
_jspService , and
the service method in
the parent class
HttpJspBase
calls the _jspService method of the subclass through the template method mode.
6
)
Several important local variables are defined in the
_jspService method:
pageContext , Session , application, config , out , page . Since the output of the entire page is completed by the _jspService method, these variables and parameters will take effect on the entire JSP page. This is why we can use these variables in JSP pages.
7
) The instruction specifying the document type (
page
) is finally transformed into
a response.setContentType()
method call.
8
) For each line of static content (
HTML
), call
out.write
to output.
9
) For the
java code in
<% ... %> , it will be directly converted to
the code in the Servlet class. If a static file is embedded in the Java code, call out.write to output as well.
2. Compilation process
The JSP
compilation process is as follows:
Compiler
compilation work mainly includes two parts: code generation and compilation:
code generation
1
)
Compiler saves
various configurations during JSP page compilation
through a
PageInfo
object , which can be
It may come from the initialization parameters of
the Web
application, and may also come from
the instruction configuration (such as page , include) of the
JSP page
.
2
) Call
ParserController
to parse the instruction node, verify whether it is legal, and save the configuration information to PageInfo to control code generation.
3
) Call
ParserController
to parse the entire page. Since
JSP
is parsed line by line, a specific Node
object will be created for each line. Such as static text (TemplateText),
Java
code (
Scriptlet
), custom tags (CustomTag
),
Include
instructions (IncludeDirective).
4
) Verify the legality of all nodes except instructions, such as scripts, custom tags,
EL
expressions, etc.
5
) Collect page configuration information of other nodes except instructions.
6
) Compile and load the tags that the current
JSP
page depends on
7
) For the
EL expression of the
JSP page
, generate the corresponding mapping function.
8
) Generate
the source code of the Servlet class corresponding to the
JSP page
compile
After the code generation is complete,
Compiler
will also generate
SMAP
information. If configured to generate
SMAP
information,
The Compiler
will write
the SMAP
information to
the class
file during the compilation phase.
In the compilation phase,
the two implementations of
Compiler ,
AntCompiler and JDTCompiler , respectively call the
API
for source code compilation.
For
AntCompiler
, the task of constructing an
Ant
javac
completes the compilation.
For
JDTCompiler
, call
org.eclipse.jdt.internal.compiler.Compiler
to complete the compilation.