org.apache.jasper.servlet.JspServletWrapper的service()方法包括了编译,载入和执行Servlet几个步骤,如下所示:
- public void service(HttpServletRequest request, HttpServletResponse response, boolean precompile)
- throws ServletException, IOException, FileNotFoundException {
- try {
- if (ctxt.isRemoved()) {
- throw new FileNotFoundException(jspUri);
- }
- if ((available > 0L) && (available < Long.MAX_VALUE)) {
- if (available > System.currentTimeMillis()) {
- response.setDateHeader("Retry-After", available);
- response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, Localizer
- .getMessage("jsp.error.unavailable"));
- return;
- } else {
- // Wait period has expired. Reset.
- available = 0;
- }
- }
- // (1) 编译
- if (options.getDevelopment() || firstTime) {
- synchronized (this) {
- firstTime = false;
- // The following sets reload to true, if necessary
- ctxt.compile();
- }
- } else {
- if (compileException != null) {
- // Throw cached compilation exception
- throw compileException;
- }
- }
- // (2) 载入Servlet类文件
- getServlet();
- // 如果是预编译,那么直接返回
- if (precompile) {
- return;
- }
- } catch (ServletException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (IOException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (IllegalStateException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (Exception ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw new JasperException(ex);
- }
- }
- try {
- // (3) 调用Servlet处理请求
- if (theServlet instanceof SingleThreadModel) {
- synchronized (this) {
- theServlet.service(request, response);
- }
- } else {
- theServlet.service(request, response);
- }
- } catch (UnavailableException ex) {
- String includeRequestUri = (String) request
- .getAttribute("javax.servlet.include.request_uri");
- if (includeRequestUri != null) {
- throw ex;
- } else {
- int unavailableSeconds = ex.getUnavailableSeconds();
- if (unavailableSeconds <= 0) {
- unavailableSeconds = 60; // Arbitrary default
- }
- available = System.currentTimeMillis() + (unavailableSeconds * 1000L);
- response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, ex.getMessage());
- }
- } catch (ServletException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (IOException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (IllegalStateException ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw ex;
- }
- } catch (Exception ex) {
- if (options.getDevelopment()) {
- throw handleJspException(ex);
- } else {
- throw new JasperException(ex);
- }
- }
- }
#compile()方法实现了对JSP文件向java类(Servlet)的编译,源代码如下所示:
- public void compile() throws JasperException, FileNotFoundException {
- // 创建"jspCompiler"的实例
- createCompiler();
- // 判断是否过期,即是否需要重新编译,这个方法中主要用源代码和编译后的文件的修改时间等因素进行判断
- if (jspCompiler.isOutDated()) {
- try {
- jspCompiler.removeGeneratedFiles();
- jspLoader = null;
- // 执行编译
- jspCompiler.compile();
- // 设定reload标志为true,让#getServlet()方法载入新的类
- jsw.setReload(true);
- jsw.setCompilationException(null);
- } catch (JasperException ex) {
- // Cache compilation exception
- jsw.setCompilationException(ex);
- throw ex;
- } catch (Exception ex) {
- JasperException je = new JasperException(
- Localizer.getMessage("jsp.error.unable.compile"),
- ex);
- // Cache compilation exception
- jsw.setCompilationException(je);
- throw je;
- }
- }
- }
可以看出,JSP页面没有修改的前提下Tomcat是不会对JSP进行多次编译的,只在第一次调用它的时候编译。
看完#compile()后,再来看一下#getServlet(),它载入了前面编译生成的Servlet类。
- public Servlet getServlet() throws ServletException, IOException, FileNotFoundException {
- if (reload) {
- synchronized (this) {
- if (reload) {
- // 销毁旧的Servlet
- destroy();
- Servlet servlet = null;
- try {
- // 载入Servlet
- servletClass = ctxt.load();
- servlet = (Servlet) servletClass.newInstance();
- AnnotationProcessor annotationProcessor = (AnnotationProcessor) config
- .getServletContext().getAttribute(
- AnnotationProcessor.class.getName());
- if (annotationProcessor != null) {
- annotationProcessor.processAnnotations(servlet);
- annotationProcessor.postConstruct(servlet);
- }
- } catch (IllegalAccessException e) {
- throw new JasperException(e);
- } catch (InstantiationException e) {
- throw new JasperException(e);
- } catch (Exception e) {
- throw new JasperException(e);
- }
- // Servlet初始化
- servlet.init(config);
- if (!firstTime) {
- ctxt.getRuntimeContext().incrementJspReloadCount();
- }
- theServlet = servlet;
- // reload值复原
- reload = false;
- }
- }
- }
- return theServlet;
- }
通过这个类,获得了一个"theServlet"实例作为JSP编译之后的Servlet引用,并且在JSP没有改动前,这个实例是不需要重新生成的。
通过这两个步骤后,最后调用了JSP编译后的Servlet类的#service()方法去处理请求。至此,Tomcat的请求处理结束了。
本文介绍了Tomcat中JSP页面的处理流程,包括编译、加载和执行Servlet等关键步骤。通过分析JspServletWrapper的service()方法,揭示了JSP如何被转化为Servlet并响应客户端请求。
1327

被折叠的 条评论
为什么被折叠?



