你了解Tomcat是怎样处理Jsp文件的吗?

上一篇文章我们了解到,Tomcat使用DefaultServlet处理所有的静态资源(回复静态两个字查看)。本篇我们来看看,jsp文件是如何被处理的。

和DefaultServlet类似,jsp的处理也不需要我们单独配置,而是在conf/web.xml中做为全局配置存在。其对应的处理类为JspServlet,用于处理所有的Jsp请求。其url-pattern是*.jsp和*.jspx。

但与DefaultServlet所不同的是,jsp文件的特殊性

我们知道jsp和html类似,最终页面展现是根据页面内的元素渲染生成。

本质上,jsp是一种特殊的Servlet文件,其在收到请求时,将页面内的各类元素编译,在工作目录生成一个Servlet文件。

而这一个工作过程,对我们使用者是透明的。整个过程在后台执行完,走和Servlet类似的流程返回浏览器

整个工作的流程可以归纳成下列的步骤:

  1. 对相应的jsp页面的请求被JspServlet拦截

  2. 执行JspServlet的service方法

  3. 获取指定的Jsp的Compiler

  4. 判断jsp文件对应的Servlet文件是否成生,是否过期

  5. 初次请求或者已过期,生成Servlet文件

  6. 调用生成的jsp的Servlet类内的_jspService方法

  7. 后续的流程和普通的Servlet一致

对照上面的流程,只有同jsp生成Servlet这一步,对于我们较为陌生。下面从代码的角度,来看下Tomcat内部的工作过程。

public void compile() throws JasperException, FileNotFoundException {

createCompiler();

if (jspCompiler.isOutDated()) {

jspCompiler.removeGeneratedFiles();

jspLoader = null;

jspCompiler.compile();

jsw.setReload(true);

jsw.setCompilationException(null);

}

在判断文件是初始请求或者已经过期后,调用编译器,生成Servlet文件。生成的文件内容类似下面的样子


文件位于Tomcat的work/Catalina目录下,对应的abc.jsp文件,生成的Servlet文件名则为abc_jsp.java

创建编译器的部分如下,可见其使用的是Eclipse的JDTCompiler


对应的生成代码如下:

public static void generate(ServletWriter out, Compiler compiler,

Node.Nodes page) throws JasperException {

Generator gen = new Generator(out, compiler);

if (gen.isPoolingEnabled) {

gen.compileTagHandlerPoolList(page);

}

gen.generateCommentHeader(); //生成文件头注释

if (gen.ctxt.isTagFile()) {

JasperTagInfo tagInfo = (JasperTagInfo) gen.ctxt.getTagInfo();

gen.generateTagHandlerPreamble(tagInfo, page);

if (gen.ctxt.isPrototypeMode()) {

return;

}

gen.generateXmlProlog(page);

gen.fragmentHelperClass.generatePreamble();

page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out,

gen.methodsBuffered, gen.fragmentHelperClass));

gen.generateTagHandlerPostamble(tagInfo);

} else {

gen.generatePreamble(page);

gen.generateXmlProlog(page);

gen.fragmentHelperClass.generatePreamble();

page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out,

gen.methodsBuffered, gen.fragmentHelperClass));

gen.generatePostamble();

}

}

看上面的红色部分,整个编译生成的过程,就是完整的输出字符流到文件的过程。不信你看下面的内容,就是生成文件头注释的代码。

private void generateCommentHeader() {

out.println("/*");

out.println(" * Generated by the Jasper component of Apache Tomcat");

out.println(" * Version: " + ctxt.getServletContext().getServerInfo());

out.println(" * Generated at: " + timestampFormat.format(new Date()) +

" UTC");

out.println(" * Note: The last modified time of this file was set to");

out.println(" * the last modified time of the source file after");

out.println(" * generation to assist with modification tracking.");

out.println(" */");

}

// Generate class declaration //生成类的声明部分

out.printin("public final class ");

out.print(servletClassName);

out.print(" extends ");

out.println(pageInfo.getExtends());

out.printin(" implements org.apache.jasper.runtime.JspSourceDependent,");

out.println();

out.printin(" org.apache.jasper.runtime.JspSourceImports");

if (!pageInfo.isThreadSafe()) {

out.println(",");

out.printin(" javax.servlet.SingleThreadModel");

}

out.println(" {");

out.pushIndent();

整个请求流程,我画了一个时序图,在后台回复jsp时序图,即可获取下载链接。


如果感觉有用,欢迎转发到朋友圈,让更多朋友了解。

扫描下方二维码,关注本公众号,获取更多精彩内容。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值