主要流程图如下:
流程说明:
1.客户端发送jsp请求;
2.服务端接受并解析jsp请求;
3.服务端检查jsp是否已经访问过;
4.服务端检查是否需要编译;若需要编译,则编译器将jsp编译成servlet的java源码并编译成class;
5.服务端检查是否需要加载jsp编译的servlet;若需要加载,则新建JasperLoader,加载并初始化servlet。
6.服务端调用jsp编译的servlet的service方法;生成响应内容
7.服务端将响应内容返回至客户端。
相关配置
BES中JSP网页由JspServlet处理,可以通过web.xml配置JspServlet。其中常用jsp编译相关初始化参数如下:
参数 |
说明 |
development |
默认值为true,即开发模式,表明jsp开发中,若更改了jsp,则根据modificationTestInterval参数检查是否重编译jsp。 若设置为false,表示生产模式,可以设置checkInterval大于0,开启后台线程每隔checkInterval时间,根据modificationTestInterval参数检查是否重编译jsp。 |
checkInterval |
后台单独线程检查生产模式下jsp是否需要被重新编译的时间间隔,默认值为0,单位为秒。 若该参数设置大于0且development为false时,开启检查线程并根据modificationTestInterval参数再次检查是否重编译jsp,否则不开启检查编译线程。 |
modificationTestInterval |
默认值为0,单位为秒,即每次检查是否编译jsp时,直接对比jsp文件和jsp编译的class的时间戳,若jsp文件时间戳大于编译的class的时间戳,则重新编译jsp。 若该参数设置大于0,则每隔该参数指定时间再对比jsp文件和jsp编译的class的时间戳,若jsp文件时间戳大于编译的class的时间戳,则重新编译jsp。 |
生产模式配置:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>development</param-name> <param-value>false</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet> |
编译时机
编译方式 |
编译时机 |
后台单独线程编译 |
前置条件:JspServlet配置为生产模式(development为false), checkInterval大于0。 编译时机:请求处理线程找到jsp文件后,编译成servlet,在初始化servlet时,启动后台编译线程。然后,每隔checkInterval时间再检查是否重新编译jsp。 检查方法: 每隔modificationTestInterval(大于0)时间对比jsp文件和jsp编译的class的时间戳,若jsp文件时间戳大于编译的class的时间戳,则重新编译jsp。否则,每次检查都对比。若对比以前编译的jsp时间戳时,发现jsp编译文件不存在,即时间戳为0,则会重新编译jsp。 |
部署加载应用线程编译 |
前置条件:部署应用时开启JSP预编译。 编译时机:应用部署时,部署加载线程编译应用中所有jsp。应用访问时,不再编译jsp。即使重启应用且jsp编译文件不存在,请求处理线程也不会再编译jsp文件。 |
请求处理线程编译 |
前置条件:JspServlet配置为生产模式。 编译时机:部署应用后,第一次访问jsp时,请求处理线程找到jsp文件后,将jsp编译成servlet;以后每次访问,请求处理线程不再重编译jsp,直到重启应用后,第一次访问jsp,请求处理线程检查是否重新编译jsp, 以后访问不再重新编译。 检查方法: 对比jsp文件和jsp编译的class的时间戳,若jsp文件时间戳大于编译的class的时间戳,则重新编译jsp。否则,每次检查都对比。若对比以前编译的jsp时间戳时,发现jsp编译文件不存在,即时间戳为0,则会重新编译jsp。 |
前置条件:JspServlet配置为开发模式(development为true)。 编译时机:部署应用后,第一次访问jsp时,请求处理线程找到jsp文件后,将jsp编译成servlet;以后每次访问jsp时,请求处理线程根据modificationTestInterval检查是否重新编译jsp。 检查方法: 每隔modificationTestInterval(大于0)时间对比jsp文件和jsp编译的class的时间戳,若jsp文件时间戳大于编译的class的时间戳,则重新编译jsp。否则,每次检查都对比。若对比以前编译的jsp时间戳时,发现jsp编译文件不存在,即时间戳为0,则会重新编译jsp。 |
编译器
由于BES存在JDTJavaCompiler和Jsr199JavaCompiler两种编译器,JDTJavaCompiler编译jsp后,会把编译生成的java和class文件放在实例的tmp中;而Jsr199JavaCompiler编译jsp后,会把编译生成的java和class放在BES定义的内存对象或数组中。
编译器 |
说明 |
|
JDTJavaCompiler |
jdk1.5运行环境中,默认使用JDT编译器,该编译器将编译的java和class文件存入实例tmp目录。 |
|
Jsr199JavaCompiler |
jdk1.6以上运行环境,默认使用JSR199编译器,该编译器是基于jdk1.6运行时编译新特性实现的,即将编译后的jsp存放在内存对象或数组中,并可以通过配置将编译的java和class存入实例的tmp目录。 BES8.1.1默认不在tmp中生成java和class文件。而BES8.2默认生成。 生成上述文件的配置方法: 通过bes-web.xml中的keepgenerated控制是否为jsp生成java文件,saveBytecode控制是否为jsp生产class文件。
|
jdk1.6及以上运行环境,常有兼容tomcat的JDTJavaCompiler编译器,将BES的Jsr199JavaCompiler改为JDTJavaCompiler。
修改方法: BES8.2打上039补丁,然后修改DMS的web.xml如下:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>compiler</param-name> <param-value>JDTJavaCompiler</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet> |
最后,重启实例,若客户应用是文件部署,则还需重新部署应用。
加载时机 |
说明 |
编译后,加载jsp的class |
第一次编译或重新编译后,第一次访问jsp,此时会新建JasperLoader加载或重新加载jsp的新class。 |
重启应用,加载jsp的class |
重启应用,会新建JasperLoader加载jsp的class。 |
当访问应用的jsp时,若需要加载jsp的class,则JasperLoader优先从内存数组中查找jsp的class,若存在,则加载内存数组中的class到jvm;若不存在,再查找实例tmp中编译的jsp的class,若在tmp中找到该文件,则加载该class到jvm中。
注:JasperLoader加载jsp到jvm,是指将编译后的jsp字节码存入方法区(也称永久代)
性能测试时,开启jsp预编译,一般可以减少编译加载jsp的次数,相对于非预编译,可以提高一定的性能。而应用在生产环境中,也该将jsp修改为生产模式,这样相对于开发模式,可以减少编译加载jsp的次数,提高一定的性能。