Jetty9源码剖析 – Handler组件 – WebAppContext

  • Post author:
  • Post category:其他


转载自ph0ly:

http://www.ph0ly.com

一、WebAppContext的概念

WebAppContext是Jetty处理器中核心的Handler,集成了众多其他基础Handler,并提供标准的JavaEE类加载机制

二、应用场景

WebAppContext提供完善的Session、Servlet、Filter的处理逻辑,它可以帮助我们构建一个标准的J2EE Web服务

三、继承体系


WebAppContext组件继承体系

可以看到WebAppContext是一个ServletContextHandler,同时实现了WebAppClassLoader.Context接口,完成系统类判断和控制类加载顺序

四、源码剖析

1 、WebAppContext的创建


WebAppContext构造函数

构造函数重载比较多,我们看到options默认会包含SESSIONS和SECURITY,也就是默认会启用SessionHandler和SecurityHandler

可以看到作为一个传统的war形式的路径传入,WebAppContext也能解析


WebAppContext构造函数详细

最终其他构造函数全部调用到这里,父类ServletContextHandler会先初始化,之后创建WebAppContext.Context,这个类其实就是在ServletContextHandler.Context基础之上扩展了一些Listener操作,这里就不在多说

然后就是异常处理器和保护路径,保护路径即Servlet规范要求的WEB-INF、META-INF目录了

2、WebAppContext的启动


WebAppContext.doStart

前面是处理MetaData,这个类在HttpParser解析这块用的比较多,这里就不细说

主要来看preConfigure和postConfigure


WebAppContext.preConfigure

第一步完成配置加载,主要是实例化默认的web-inf、web-xml、meta-inf等配置的类

第二步完成系统类加载,主要是初始化系统类名称,例如java、javax、org.xml、org.w3c等开头的包名或者具体的类

第三步完成服务端类加载,主要是初始化服务端类名称,例如org.eclipse.jetty开头的类(也有部分排除)

这里为什么会区分系统类、服务端类呢?待会儿我们一起来分析下WebAppClassLoader就明白了

如果这里没有设置过类加载器,则自动创建一个WebAppClassLoader

配置刚才的所有配置,调用了preConfigure,预配置


WebAppContext.postConfigure

postConfigure比较简单,就是前面的configurations调用postConfigure,这里不多讲

3、WebAppClassLoader的实现


WebAppClassLoader继承体系

可以看到它是一个URLClassLoader,我们来看它最核心的方法loadClass


WebAppClassLoader.loadClass


WebAppClassLoader.loadClass

先来看下Servlet规范要求,摘自Jetty官网(

http://www.eclipse.org/jetty/documentation/9.3.x/jetty-classloading.html)


Jetty类加载机制描述

1. 默认优先加载WEB-INF/lib、WEB-INF/classes,其次是父类加载器

2. 系统类如java.lang.String不需要webapp类加载器加载

3. 服务端类如Server类不应该对应用程序类加载器可见,即应用程序不应该去加载Web容器的类

======== 再回头看代码 =========

这里对同一名称的全类名类加锁,不言而喻,防止重复加载

首先是常规操作,是否加载过了,加载过就直接返回

然后就是根据是否以父类加载模式方式加载,即双亲委派模型加载(默认不是双亲委派模式)


如果是父类加载器优先:

首先调用父类加载器加载类,如果当前类不是服务端类,才返回,也就是说大部分jetty自有的类是不允许使用父类加载器

父类加载器未找到该类,则尝试webapp自身的加载方式加载


如果是应用类加载器优先:

如果不是系统类,则将类文件读入并定义类,加载完成

如果当前是系统类,例如java本身的类或者部分jetty自身实现的类,则会使用父类加载器加载,如果父类加载器仍然加载不到,会使用webapp自身加载方式尝试加载,加载不到就抛ClassNotFoundException

相信看完WebAppClassLoader后,大家应该清楚之前的systemClasses和serverClasses是干什么的了

顺便推荐一篇文章

血泪的Jetty ClassLoader

4、WebAppContext.startContext启动上下文


WebAppContext.startContext

该方法在ContextHandler.doStart触发,这里首先configure,完成各配置的configure,由于不属于核心,这里不细讲

metadata元数据比较简单,读者可以自行下来查看

之后启动webapp,其实就是调用了ServletContextHandler.startContext

五、总结

WebAppContext作为Jetty核心Handler,是我们构建Jetty标准Web必选的处理器。对于Spring Boot会在创建Server后,再创建一个JettyEmbeddedWebAppContext(其实是一个WebAppContext),从而Spring Boot能基于Jetty构建一个完整的Web应用。至此Jetty常规的传统Handler已完成分析,当然还有很多细节,感兴趣的读者下来可以自己分析,同时欢迎留言交流。后期我会增加WebSocket、Http2协议的相关知识,欢迎继续关注~