在jetty中,所有xml文件的配置使用descriptor来表达,而对这些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方法。