JSP编译成Servlet(一)语法树的生成——语法解析

一般来说,语句按一定规则进行推导后会形成一个语法树,这种树状结构有利于对语句结构层次的描述。同样Jasper对JSP语法解析后也会生成一棵树,这棵树各个节点包含了不同的信息,但对于JSP来说解析后的语法树比较简单,只有一个父节点和n个子节点。例如node1是表示形如<!-- 字符串 -->的注释节点,节点里面包含了一个表示注释字符串的属性;而node2则可能是表示形如<%= a+b %>的表达式节点,节点里面包含一个表示表达式的属性,同样地其他节点可能表示JSP的其他语法,有了这棵树我们就可以很方便地生成对应的Servlet。

 

    现在看看怎样解析生成这棵树的,

①首先定义树数据结构,其中parent指向父节点,nodes是此节点的子节点,且nodes应该是有序的列表,这样能保证与解析顺序一致。另外由于每个节点的属性不同,Node类只提供公共的部分属性,对于不同节点其他属性需要继承Node额外实现。

public class Node {

private Node parent;

private List<Node> nodes;

private String text;

    private Attributes attrs;

}

public class RootNode{}

public class CommentNode{}

public class PageNode{}

public class IncludeNode{}

public class TaglibNode{}

②其次需要一个读取JSP文件的工具类,此工具类主要提供对JSP文件的字符操作,其中有个cursor变量用于表示目前解析位置,主要的方法则包括判断是否到达文件末尾的hasMoreInput方法,获取下个字符的nextChar方法,获取某个范围内的字符组成的字符串getText方法,匹配是否包含某字符串的matches方法,跳过空格符的skipSpaces方法,以及跳转到某个字符串的skipUntil方法。有了这些辅助操作就可以开始读取解析语法了。

public class JspReader{

   private int cursor;

   public int getCursor(){ return cursor ; }

   boolean hasMoreInput(){...}

   public int nextChar(){...}

   public String getText(int start,int end){...}

   boolean matches(String string){...}

   int skipSpaces(){...}

   int skipUntil(String limit){...}

}

③需要一个JSP语法解析器对JSP进行解析,这里为了简单说明只解析<!-- .... -->注释语法、<@page .../%>页面指令、<%@include.../%>包含指令、<%@taglib.../%>标签指令。假设对index.jsp进行语法解析,匹配到<%--则表示注释语法,获取其中的注释文字并创建commentNode节点作为根节点的子节点,如果匹配到<%@则有三种可能,所以需要进一步解析,即对应页面指令、包含指令和标签指令等的解析。最后解析出来的就是如图所示的一棵语法树。

public class Parser{

    public RootNode parse(){

        JspReader reader = new JspReader("index.jsp");

        RootNode root = new RootNode();

        while (reader.hasMoreInput()) {

            if (reader.matches("<%--")) {

                int start = reader.getCursor();

                reader.skipUntil("--%>");

                int end = reader.getCursor();

                CommentNode commentNode = new CommentNode ();

                commentNode.setText(reader.getText(start, stop));

                commentNode.setParent(parent);

                parent.getList().add(commentNode);

            } else if (reader.matches("<%@")) {

                if (reader.matches("page")) {

                    解析<%@page.../%>里面的属性生成attrs

                    PageNode pageNode = new PageNode ();

                    pageNode.setAttributes(attrs);

                    pageNode.setParent(parent);

                    parent.getList().add(pageNode);

                } else if (reader.matches("include")) {

                    解析<%@include.../%>里面的属性生成attrs

                    IncludeNode includeNode = new IncludeNode ();

                    includeNode.setAttributes(attrs);

                    includeNode.setParent(parent);

                    parent.getList().add(includeNode);

                } else if (reader.matches("taglib")) {

                    解析<%@taglib.../%>里面的属性生成attrs

                    TaglibNode taglibNode = new TaglibNode ();

                    taglibNode.setAttributes(attrs);

                    taglibNode.setParent(parent);

                    parent.getList().add(taglibNode);

                }

            }

        }

        return root;

    }

}

点击订购作者《Tomcat内核设计剖析》

时间: 2024-10-27 04:36:08

JSP编译成Servlet(一)语法树的生成——语法解析的相关文章

JSP编译成Servlet(四)JSP与Java行关系映射

我们知道java虚拟机只认识class文件,要在虚拟机上运行就必须要遵守class文件格式,所以JSP编译成servlet后还需要进一步编译成class文件,但从JSP文件到java文件再到class文件的过程需要考虑的事情比较多,其中一个比较重要的就是调试问题,由于语法不一样,jsp某行执行的逻辑怎样与java文件对应起来,这样在JVM执行过程发生异常或错误才能找到JSP对应的行,提供一个友好的调试信息.类似的,jsp文件名编译后的java文件名同样也要有映射关系.     总的来说,为了解决

JSP编译成Servlet(三)JSP编译后的Servlet

JSP编译后的Servlet类会是怎样的呢他们之间有着什么样的映射关系在探讨JSP与Servlet之间的关系时先看一个简单的HelloWorld.jsp编译成HelloWorld.java后会是什么样. ①HelloWorld.jsp <%@ page contentType="text/html; charset=gb2312" language="java" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD

JSP编译成Servlet(二)语法树的遍历——访问者模式

语法树可以理解成是一种数据结构,假如某些语句已经被解析成一棵语法树,那么接下来就是要对此语法树进行处理,但考虑到不将处理操作与数据结构混合在一块,我们需要一种方法将其分离.其实对于语法树的处理最典型的处理模式就是访问者模式,它能很好的将数据结构与处理分离,提供了很好的解耦作用,让我们可以在生成语法树的过程只需关注如何构建相关的数据结构,而在对语法树处理的时候只需关注处理的逻辑,是一种非常巧的设计模式,接下来通过一个简单的代码案例看看如何实现一个访问者模式. ①定义访问者操作方法接口,声明所有访问

如何使用ant调用WebSphere的编译器将jsp编译成jar包?

问题描述 我们现有的项目是运行在tomcat5下,jsp是通过使用tomcat提供的org.apache.jasper.JspC编译工具将JSP页面的预编译.把所有JSP编译后得到的.class打包成一个xxx.jar包,放在我们应用的lib中.然后在web.xml中分别设置为servlet,再映射到某个xxx.jsp的URL上.build.xml文件如下:<projectname="WebappPrecompilation"default="all"base

脱离ws_ant直接使用Ant调用WebSphere编译器将jsp编译成class

http://yulimin.javaeye.com/blog/412504   引子: 引用 tomcat5下,jsp是通过使用tomcat提供的org.apache.jasper.JspC编译工具将JSP 页面的预编译 在WAS当中是通过 Java代码 com.ibm.websphere.ant.tasks.JspC   完整的Ant脚本 build.xml 文件内容 Java代码 <?xml version="1.0" encoding="UTF-8"?

JSP转译成Servlet详细过程

JSP转译成Servlet详细过程 JSP转译成Servlet详细过程   JSP是Servlet的扩展,在没有JSP之前,就已经出现了Servlet技术.Servlet是利用输出流动态生成HTML页面,包括每一个HTML标签和每个在HTML页面中出现的内容.     由于包括大量的HTML标签.大量的静态文本及格式等,导致Servlet的开发效率极为低下.所有的表现逻辑,包括布局.色彩及图像等,都必须耦合在Java代码中,这的确让人不胜其烦.JSP的出现弥补了这种不足,JSP通过在标准的HTM

选择jsp而不是servlet作为BS前台主流方案是JAVA的战略性方向错误

js|servlet|错误|战略|主流  原文许多人认为JSP是JAVA向微软ASP挑战的成功产品,到今天,围绕着JSP方案发展出了TAG/EL等技术,JSP作为JAVA的BS前台界面方案看来已经是无法逆转.但在我看来,JAVA选择JSP这种表达形式,恰恰是它最失败的地方,是对ASP的一种拙劣的模仿,它本来可以做得更好的,甚至可能据此让微软彻底退出服务器领域,但最终,却可能成为足以令JAVA最终失败的重大战略方向性错误.JAVA到今天仍具有微软所有语言所不具备的优点,就以C#而言,只不过是形似而

把JSP预编译成class文件进行JSP文件的保护

js|编译 在Weblogic中发布Web Application工程时,为了保护JSP文件避免未经授权的访问和窥视,可以用weblogic.jspc把JSP文件precompile成为servlet文件,放到WEB-INF/classes目录下.基于Servlet的声明,WEB-INF不作为Web应用的公共文档树的一部分.因而,WEB-INF目录下的资源不是为客户直接服务的,这样就可以一定程度上保证JSP的安全. 具体的实现步骤如下(Weblogic for linux): 1.用weblog

JSP编译指令page、include详解

 这篇文章主要介绍了JSP编译指令page.include,有需要的朋友可以参考一下 1. JSP指令   分类:1).page  2).include  3).taglib   语法:  <%@ 指令名称  属性1="值1" .....%>   2. Page编译指令:   • 作用:利用Page编译指令可以设置JSP的页面属性.通常位于JSP页面的顶端,对同一个页面可以有多个page指令. • page指令语法格式:    代码如下: <%@page   [lan