Tomcat 架构分析(三) Jasper模块

Tomcat 架构分析(三) Jsper模块



前言:Jsper模块: 负责jsp页面的解析、jsp属性的验证,同时也负责将jsp页面动态转换为java代码并编译成class文件。


1.简介

Tomcat 8.5使用Jasper 2 JSP引擎来实现JavaServer Pages 2.3规范。
Jasper 2被重新设计,显著改善了Jasper的表现。 除了一般的代码改进之外,以下的更改还包括:

  • JSP Custom Tag Pooling - 为JSP自定义标记实例化的java对象现在可以被池化和重用。这极大地提高了使用自定义标记的JSP页面的性能。
  • Background JSP compilation - 如果您对已经编译过的JSP页面进行了更改,那么Jasper 2可以在后台重新编译该页面。以前编译的JSP页面仍然可用来服务请求。一旦新页面被成功编译,它将取代旧页面。这有助于提高生产服务器上JSP页面的可用性。
  • Recompile JSP when included page changes - Jasper 2现在可以检测到,从JSP中包含的一个页面已经改变了,然后重新编译了父JSP。
  • JDT used to compile JSP pages - 现在,Eclipse JDT Java编译器被用于执行JSP Java源代码编译。这个编译器从容器类加载器加载源依赖项。Ant和javac仍然可以使用。

Jasper是org.apache.jasper.servlet.JspServlet使用servlet实现类 下面的coding是对JSPServlet源码的分析。

/**
 * Copyright © 2017 http://blog.csdn.net/noseparte © Like the wind, like rain
 * @Author Noseparte
 * @Compile 2017年12月7日 -- 下午4:34:36
 * @Version 1.0
 * @Description  JspServlet源码分析
 */
public class JspServlet extends HttpServlet implements PeriodicEventListener {
	
	/**
	 * @see transient修饰词释义
	 * java语言的关键字,变量修饰符,如果用transient声明一个实例变量,
	 * 当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
	 */
	private static final long serialVersionUID = 1L;
    private final transient Log log = LogFactory.getLog(JspServlet.class);	
    private transient ServletContext context;	//ServletContext对象包含在ServletConfig对象中,当servlet被初始化时,Web服务器提供servlet。
    private ServletConfig config;  //servlet容器使用的servlet配置对象在初始化期间将信息传递给servlet。
    private transient Options options; //一个类来保存所有与JSP引擎相关的init参数。
    private transient JspRuntimeContext rctxt; //用于跟踪JSP编译时文件依赖项的类
    private String jspFile;

    /**
     * javax.servlet.GenericServlet由servlet容器调用,以指示servlet正在被放置到服务中。
     * 看到Servlet.init(javax.servlet.ServletConfig)。
     * 该实现存储从servlet容器接收的ServletConfig对象,以供以后使用。
     * 当覆盖该方法的这种形式时,调用super.init(config)。
     * @param config
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.config = config;
        this.context = config.getServletContext();

        String engineOptionsName = config.getInitParameter("engineOptionsClass");

        if ((Constants.IS_SECURITY_ENABLED) && (engineOptionsName != null)) {
            this.log.info(Localizer.getMessage("jsp.info.ignoreSetting",
                    "engineOptionsClass", engineOptionsName));
            engineOptionsName = null;
        }

        if (engineOptionsName != null) {
            try {
                ClassLoader loader = Thread.currentThread()
                                           .getContextClassLoader();
                Class<?> engineOptionsClass = loader.loadClass(engineOptionsName);
                Class<?>[] ctorSig = { ServletConfig.class, ServletContext.class };
                Constructor<?> ctor = engineOptionsClass.getConstructor(ctorSig);
                Object[] args = { config, this.context };
                this.options = ((Options) ctor.newInstance(args));
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);

                this.log.warn("Failed to load engineOptionsClass", e);

                this.options = new EmbeddedServletOptions(config, this.context);
            }
        } else {
            this.options = new EmbeddedServletOptions(config, this.context);
        }

        this.rctxt = new JspRuntimeContext(this.context, this.options);

        if (config.getInitParameter("jspFile") != null) {
            this.jspFile = config.getInitParameter("jspFile");

            try {
                if (null == this.context.getResource(this.jspFile)) {
                    return;
                }
            } catch (MalformedURLException e) {
                throw new ServletException("cannot locate jsp file", e);
            }

            try {
                if (SecurityUtil.isPackageProtectionEnabled()) {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                            public Object run()
                                throws IOException, ServletException {
                                JspServlet.this.serviceJspFile(null, null,
                                    JspServlet.this.jspFile, true);

                                return null;
                            }
                        });
                } else {
                    serviceJspFile(null, null, this.jspFile, true);
                }
            } catch (IOException e) {
                throw new ServletException("Could not precompile jsp: " +
                    this.jspFile, e);
            } catch (PrivilegedActionException e) {
                Throwable t = e.getCause();

                if ((t instanceof ServletException)) {
                    throw ((ServletException) t);
                }

                throw new ServletException("Could not precompile jsp: " +
                    this.jspFile, e);
            }
        }

        if (this.log.isDebugEnabled()) {
            this.log.debug(Localizer.getMessage("jsp.message.scratch.dir.is",
                    this.options.getScratchDir().toString()));

            this.log.debug(Localizer.getMessage(
                    "jsp.message.dont.modify.servlets"));
        }
    }

    /**
     * 返回JspServletWrappers存在的jsp数量
     * @return
     */
    public int getJspCount() {
        return this.rctxt.getJspCount();
    }

    /**
     * 重新设置JSP重新加载计数器。
     * @param count
     */
    public void setJspReloadCount(int count) {
        this.rctxt.setJspReloadCount(count);
    }

    /**
     * 获取已重新加载的jsp的数量。
     * @return
     */
    public int getJspReloadCount() {
        return this.rctxt.getJspReloadCount();
    }

    /**
     * 获得JSP限制队列中JSP的数量
     * @return
     */
    public int getJspQueueLength() {
        return this.rctxt.getJspQueueLength();
    }

    /**
     * 获得已卸载的jsp的数量。
     * @return
     */
    public int getJspUnloadCount() {
        return this.rctxt.getJspUnloadCount();
    }

    boolean preCompile(HttpServletRequest request) throws ServletException {
        String queryString = request.getQueryString();

        if (queryString == null) {
            return false;
        }

        int start = queryString.indexOf(Constants.PRECOMPILE);

        if (start < 0) {
            return false;
        }

        queryString = queryString.substring(start +
                Constants.PRECOMPILE.length());

        if (queryString.length() == 0) {
            return true;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值