深入Jetty源码之DescriptorProcessor实现

概述

在Jetty中,所有XML文件的配置使用Descriptor来表达,而对这些Descriptor的处理使用DescriptorProcessor来实现。

Descriptor和DescriptorProcessor类图

Descriptor实现

Descriptor可以表达一个*.tld文件(TldDescriptor)、一个/META-INF/web.xml文件(WebDescriptor),一个/org/eclipse/jetty/webapp/webdefault.xml(DefaultsDescriptor),一个/META-INF/web-fragment.xml文件(FragmentDescriptor),一个override-web.xml文件(OverrideDescriptor)。其中TldDescriptor在TagLibConfiguration的TagListener中查找并使用TldProcessor解析;WebDescriptor在WebXmlConfiguration的preConfigure中查找,并设置到MetaData的webXmlRoot字段中,并更新MetaData的ordering字段,其资源文件可以手动设置WebAppContext的descriptor字段,或者未设置而使用META-INF/web.xml文件;DefaultsDescriptor也在WebXmlConfiguration的preConfigure中查找,并设置到MetaData的webDefaultsRoot字段中,并更新MetaData的ordering字段,其资源文件可以手动设置WebAppContext中的defaultsDescriptor字段,或未设置而默认使用/org/eclipse/jetty/webapp/webdefault.xml文件;OverrideDescriptor也在WebXmlConfiguration的preConfigure中查找,并设置到MetaData的webOverrideRoots集合中,并更新MetaData中的ordering字段,其资源文件可以手动设置,如果未设置,则忽略;而FragmentDescriptor则是在FragmentConfiguration中的preConfigure中添加到MetaData的webFragmentResourceMap、webFragmentNameMap以及webFragmentRoots中,如果MetaData的ordering为null,且不为absolute,则更新ordering字段。

 

每个Descriptor使用一个xml的Resource实例作为构造函数构建,并使用XmlParser将其解析成类DOM树,保存树的root节点引用。

 

除了TldDescriptor在TagLibConfiguration中已经处理完成,其他的Descriptor使用StandardDescriptorProcessor以及PlusDescriptorProcessor来处理,其中StandardDescriptorProcessor在WebXmlConfiguration的configure方法中注册到MetaData的descriptorProcessors集合中,而PlusDescriptorProcessor在PlusConfiguration的configure方法中注册到MetaData中。并在MataData的resolve方法中使用注册的DescriptorProcessor依次解析webDefaultsRoot、webXmlRoot、webOverrideRoots以及webFragmentRoots对应的Descriptor实例。

DescriptorProcessor实现

DescriptorProcessor只有一个process方法,他遍历传入的Descriptor的所有Node,并对不同Node做相应的处理。在IterativeDescriptorProcessor的采用了非常巧妙的实现方法,即使用一个visitors的Map,包含节点的tag到相应处理方法的映射,因而在IterativeDescriptorProcessor的实现中,它遍历Descriptor的节点树,对每个节点查找对应的处理方法,并调用查找到的方法,其子类的实现只需要注册这个visitors的Map,然后实现注册的方法即可;为了增加可扩展性,在解析前和解析后分别添加了start、end的插入点。

如在StandardDescriptorProcessor中,注册了如下几个visitor方法:
context-param => visitContextParam 向WebAppContext添加InitParam信息。

display-name => visitDisplayName 向WebAppContext设置displayName属性。
servlet => visitServlet 向ServletHandler中添加一个新的ServletHolder,并配置其servlet-name、init-param、servlet-class、jsp-file、load-on-startup、security-role-ref、run-as、async-supported、enabled、multipart-config等信息;如果id设置为jsp,则会在InitParam中配置scratchdir、classpath参数,以及为Jasper配置com.sun.appserv.jsp.classpath参数,而在WebAppContext中为Jasper配置org.apache.catalina.jsp_classpath属性;用于注册org.apache.jasper.servlet.JspServlet;对jsp-file,设置其forcePath为该值。

servlet-mapping=> visitServletMapping 配置ServletHandler中servlet-name对应的ServletMapping信息。

session-config => visitSessionConfig 设置SessionHandler中SessionManager的一些配置信息。

mime-mapping => visitMimeMapping 设置WebAppContext中extension到mimeType的映射。

welcome-file-list => visitWelcomeFileList 设置WebAppContext中的welcomeFiles。

locale-encoding-mapping-list => visitLocaleEncodingList 设置WebAppContext中locale到encoding的映射关系。

error-page => visitErrorPage 设置ErrorPageErrorHandler中errorCode或exceptionType到location的映射关系。

taglib => visitTagLib 设置taglib-uri到taglib-location的映射关系,即WebAppContext中taglib-uri是taglib-location的alias。

jsp-config => visitJspConfig 将jsp-property-group下url-pattern映射到JspServlet中。

security-constraint => visitSecurityConstraint 向SecurityHandler中添加ConstraintMapping。

login-config => visitLoginConfig 向SecurityHandler中设置AuthMethod、RealmName属性,以及对FORM方法的验证,设置login、error页面的InitParam。

security-role => visitSecurityRole 向SecurityHandler中注册定义的role集合。

filter => visitFilter 向ServletHandler注册FilterHolder,并配置filter-name、filter-class、init-param、async-supported等信息。

filter-mapping => visitFilterMapping 向ServletHandler注册FilterMapping信息。

listenr => visitListener 向WebAppContext注册EventListener。

distributable => visitDestributable 设置WebDescriptor的distributable属性为true。

 

在PlusDescriptorProcessor中,首先在其start方法中会向WebAppContext注册InjectionCollection、LifeCycleCallbackCollection、RunAsCollection(该属性在RunAsAnnotationHandler中使用)属性,并且注册了以下几个visitor方法:
env-entry => visitEnvEntry 向InjectionCollection添加Injection实例,其中jndiName为env-entry-name定义的值,valueClass为env-entry-type定义的类型,而targetClass、targetName为injection-target下的injection-target-class、injection-target-name中定义的值,每个injection-target生成一个Injection实例。同时将env-entry-value中定义的值绑定到java:com/env/<name>对应的资源中。(Injection实例也可以使用@Resource注解注册,并在ResourceAnnotationHandler中解析)

resource-ref => visitResourceRef 向InjectionCollection添加Injection实例,其中jndiName为res-ref-name,typeClass为res-type,并绑定该引用资源。

resource-env-ref => visitResourceEnvRef 向InjectionCollection添加Injection实例,其中jndiName为resource-env-ref-name,typeClass为resource-env-ref-type,并绑定该env引用资源。

message-destination-ref => visitMessageDestinationRef 向InjectionCollection添加Injection实例,其中jndiName为message-destination-ref-name,typeClass为message-destination-type,并绑定该message-destination引用资源。

post-construct => visitPostConstruct 向LifeCycleCallbackCollection注册一个PostConstructCallback,其targetClass由lifecycle-callback-class定义,而method由lifecycle-callback-method定义(该PostConstructCallback也可以使用@PostConstruct的Annotation方式注册,并在PostConstructAnnotationHandler中解析)。

pre-destroy => visitPreDestroy 向LifeCycleCallbackCollection注册PreDestroyCallback,其targetClass由lifecycle-callback-class定义,methodName由lifecycle-callback-method定义(该PreDestroyCallback也可以使用@PreDestroy注解注册,并在PreDestroyAnnotationHandler中解析)。

 

所有以上注册的RunAsCollection、InjectionCollection、LifeCycleCallbackCollection都在PlusDecorator中使用,PlusDecorator类实现Decorator方法,在所有的decorate实现方法中,使用RunAsCollection向ServletHolder中注册配置的roleName(感觉这里有bug,应该是decorate一个Servlet而不是ServletHolder);使用InjectionCollection向Servlet、Filter、EventListener注入JNDI对应的值;使用LifeCycleCallbackCollection调用所有注册的PostConstruct方法。而在destroyServlet、Filter实例时,使用LifeCycleCallbackCollection调用素有注册的PreDestroy方法。

时间: 2024-08-14 21:50:38

深入Jetty源码之DescriptorProcessor实现的相关文章

深入Jetty源码之ContextHandler

概述 ContextHandler继承自ScopedHandler,它是Jetty中实现对一个Web Application的各种资源进行管理,并串联实现整个Servlet框架的类,比如它部分实现了ServletContext接口,并且在其doScope方法中为当前Request的执行提供了相应的环境,如设置servletPath.pathInfo.设置ServletContext到ThreadLocal中.在Jetty中,Servlet的执行流程和框架由ServletHandler实现,Sec

深入Jetty源码之Handler总述

Handler概述 Handler是Jetty中的核心接口,它用于处理所有连接以外的逻辑,比如对Servlet框架的实现,以及用户自定义的Handler等,它继承自LifeCycle和Destroyable接口,只有一个主要方法:handle,包含Request和Response实例.在深入Jetty源码之Connection中有写道在HttpConnection的handleRequest()方法中会最终调用Server的handle()或handleAsync()方法,并且传入HttpCon

深入Jetty源码之Connector

Connector概述 Connector是Jetty中可以直接接受客户端连接的抽象,一个Connector监听Jetty服务器的一个端口,所有客户端的连接请求首先通过该端口,而后由操作系统分配一个新的端口(Socket)与客户端进行数据通信(先握手,然后建立连接,但是使用不同的端口).不同的Connector实现可以使用不同的底层结构,如Socket Connector.NIO Connector等,也可以使用不同的协议,如Ssl Connector.AJP Connector,从而在不同的C

深入Jetty源码之Servlet框架及实现(ServletRequest、ServletResponse)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性).在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互的

深入Jetty源码之Connection

概述 当Jetty中的Connector收到一个客户端的连接时(ServerSocket或ServerSocketChannel的accept()方法返回),Connector会首先创建一个ConnectedEndPoint用于和连接的底层(Socket.Channel)打交道(读写数据),在创建的ConnectedEndPoint时会同时使用该EndPoint创建相应类型的Connection,然后会创建一个Task仍给线程池,最终线程池会启动一个线程启动这个Task,而在这个Task中调用C

深入Jetty源码之HttpGenerator

基于抽象和聚合原则,Jetty中需要一个单独的类来专门处理HTTP响应消息和请求消息的生成和发送,Jetty的作者将该抽象(接口)命名为Generator,它有两个实现类:HttpGenerator和NestedGenerator.其类图如下: Generator接口 HTTP请求消息分为请求行.消息报头.请求正文三部分,HTTP响应消息分为状态行.消息报头.消息正文.在HTTP请求消息和响应消息格式的唯一区别是请求行和状态行,因而只需要将这一行的内容区分开来,其他的可以共享逻辑. 请求行和响应

深入Jetty源码之Servlet框架及实现(AsyncContext、RequestDispatcher、HttpSession)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性).在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互的

深入Jetty源码之Servlet框架及实现(ServletContext)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性). 在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互

深入Jetty源码之Servlet框架及实现(Servlet、Filter、Registration)

概述 Servlet是Server Applet的缩写,即在服务器端运行的小程序,而Servlet框架则是对HTTP服务器(Servlet Container)和用户小程序中间层的标准化和抽象.这一层抽象隔离了HTTP服务器的实现细节,而Servlet规范定义了各个类的行为,从而保证了这些"服务器端运行的小程序"对服务器实现的无关性(即提升了其可移植性).在Servlet规范有以下几个核心类(接口):ServletContext:定义了一些可以和Servlet Container交互的