【转载】http://www.bingfengsa.com/old/archives/9921.html
根据源码,我看到JSP编译的顺序是这样的:
1– getJspConfigPageEncoding
2– determineSyntaxAndEncoding
3– 解析成 Node.Nodes parsedPage 对象,即取出所有节点
4– 解析每个节点
第1步,是从web.xml等配置文件中去读取配置(里面有个<jsp-config>配置),如果配置时设置了统一编码,则使用这种类型的编码,第2步,是根据文件来获取编码,注意看如下一段代码:
if ((jspReader.matches(“tag ”)) || (jspReader.matches(“page”)))
{
jspReader.skipSpaces();
Attributes attrs = Parser.parseAttributes(this, jspReader);
encoding = getPageEncodingFromDirective(attrs, ”pageEncoding”);
if (encoding != null) {
break;
}
encoding = getPageEncodingFromDirective(attrs, ”contentType”);
if (encoding != null) {
saveEncoding = encoding;
}
}
}
程序首先判断有无编译指令tag或者page,如果有,则检查编译指令是否指定了pageEncoding属性或者contentType属性。根据这种逻辑,可知如下这种写法:
<%@ page contentType=”text/html;charset=utf-8″ pageEncoding=”UTF-8″%>
其实是重复指定了编码,解析时会以pageEncoding为准。
第4步,解析每个节点:
while (reader.hasMoreInput()) {
parser.parseElements(root);
}
这里又分为几个步骤,先看程序:
private void parseElements(Node parent)
throws JasperException
{
this.start = this.reader.mark();
if (this.reader.matches(“<%–”)) {
parseComment(parent);
} else if (this.reader.matches(“<%@”)) {
parseDirective(parent);
} else if (this.reader.matches(“<jsp:directive.”)) {
parseXMLDirective(parent);
} else if (this.reader.matches(“<%!”)) {
parseDeclaration(parent);
} else if (this.reader.matches(“<jsp:declaration”)) {
parseXMLDeclaration(parent);
} else if (this.reader.matches(“<%=”)) {
parseExpression(parent);
} else if (this.reader.matches(“<jsp:expression”)) {
parseXMLExpression(parent);
} else if (this.reader.matches(“<%”)) {
parseScriptlet(parent);
} else if (this.reader.matches(“<jsp:scriptlet”)) {
parseXMLScriptlet(parent);
} else if (this.reader.matches(“<jsp:text”)) {
parseXMLTemplateText(parent);
} else if ((!(this.pageInfo.isELIgnored())) && (this.reader.matches(“${“))) {
parseELExpression(parent, ’$');
} else if ((!(this.pageInfo.isELIgnored())) && (this.reader.matches(“#{“)))
{
parseELExpression(parent, ’#');
} else if (this.reader.matches(“<jsp:”)) {
parseStandardAction(parent);
} else if (!(parseCustomTag(parent))) {
checkUnbalancedEndTag();
parseTemplateText(parent);
}
}
处理的顺序如下:
1– “<%– –%>”类型的注释
2– “<%@ %>”编译指令
3– “<jsp:directive. %>”编译指令
4– “<%! %>”声明指令
5– “<%= %>”表达式指令
6– “<% %>”嵌入脚本
7– “<jsp:text >”嵌入文本
8– “${ }”EL表达式
9– “#{ }”EL表达式
10– “<jsp: >”其他jsp动作指令
11– 自定义的tag标签
然后,再看看jsp中的java代码(ScriptingElement)是怎么执行的:
第一步:
new一个Node节点,然后把java的字符串完整地赋值给Node的text属性,然后把node添加到Parent Node 队列(List)里面。
第二步:读取这些Nodes,将其转换成java源代码,然后在调用java编译器将源代码编译成class文件。(注意:这个功能相当于是把字符串,转换成了java字节码)
这个过程,调用了SmapUtil将上面那些nodes转换成Java源文件,然后调用JDTCompiler工具类,将Java源文件编译成.class文件,我看Tomcat调用的是org.eclipse.jdt.internal.compiler.*包下面的编译工具,实际上JDK也为我们提供了自己手动编译Java文件的方法,JDK 1.6可以用javax.tools.JavaCompiler。
转载于:https://blog.51cto.com/10120275/1636673