概述
在Jetty中,所有XML文件的配置使用Descriptor來(lái)表達(dá),而對(duì)這些Descriptor的處理使用DescriptorProcessor來(lái)實(shí)現(xiàn)。
Descriptor和DescriptorProcessor類圖

Descriptor實(shí)現(xiàn)
Descriptor可以表達(dá)一個(gè)*.tld文件(TldDescriptor)、一個(gè)/META-INF/web.xml文件(WebDescriptor),一個(gè)/org/eclipse/jetty/webapp/webdefault.xml(DefaultsDescriptor),一個(gè)/META-INF/web-fragment.xml文件(FragmentDescriptor),一個(gè)override-web.xml文件(OverrideDescriptor)。其中TldDescriptor在TagLibConfiguration的TagListener中查找并使用TldProcessor解析;WebDescriptor在WebXmlConfiguration的preConfigure中查找,并設(shè)置到MetaData的webXmlRoot字段中,并更新MetaData的ordering字段,其資源文件可以手動(dòng)設(shè)置WebAppContext的descriptor字段,或者未設(shè)置而使用META-INF/web.xml文件;DefaultsDescriptor也在WebXmlConfiguration的preConfigure中查找,并設(shè)置到MetaData的webDefaultsRoot字段中,并更新MetaData的ordering字段,其資源文件可以手動(dòng)設(shè)置WebAppContext中的defaultsDescriptor字段,或未設(shè)置而默認(rèn)使用/org/eclipse/jetty/webapp/webdefault.xml文件;OverrideDescriptor也在WebXmlConfiguration的preConfigure中查找,并設(shè)置到MetaData的webOverrideRoots集合中,并更新MetaData中的ordering字段,其資源文件可以手動(dòng)設(shè)置,如果未設(shè)置,則忽略;而FragmentDescriptor則是在FragmentConfiguration中的preConfigure中添加到MetaData的webFragmentResourceMap、webFragmentNameMap以及webFragmentRoots中,如果MetaData的ordering為null,且不為absolute,則更新ordering字段。
每個(gè)Descriptor使用一個(gè)xml的Resource實(shí)例作為構(gòu)造函數(shù)構(gòu)建,并使用XmlParser將其解析成類DOM樹(shù),保存樹(shù)的root節(jié)點(diǎn)引用。
除了TldDescriptor在TagLibConfiguration中已經(jīng)處理完成,其他的Descriptor使用StandardDescriptorProcessor以及PlusDescriptorProcessor來(lái)處理,其中StandardDescriptorProcessor在WebXmlConfiguration的configure方法中注冊(cè)到MetaData的descriptorProcessors集合中,而PlusDescriptorProcessor在PlusConfiguration的configure方法中注冊(cè)到MetaData中。并在MataData的resolve方法中使用注冊(cè)的DescriptorProcessor依次解析webDefaultsRoot、webXmlRoot、webOverrideRoots以及webFragmentRoots對(duì)應(yīng)的Descriptor實(shí)例。
DescriptorProcessor實(shí)現(xiàn)
DescriptorProcessor只有一個(gè)process方法,他遍歷傳入的Descriptor的所有Node,并對(duì)不同Node做相應(yīng)的處理。在IterativeDescriptorProcessor的采用了非常巧妙的實(shí)現(xiàn)方法,即使用一個(gè)visitors的Map,包含節(jié)點(diǎn)的tag到相應(yīng)處理方法的映射,因而在IterativeDescriptorProcessor的實(shí)現(xiàn)中,它遍歷Descriptor的節(jié)點(diǎn)樹(shù),對(duì)每個(gè)節(jié)點(diǎn)查找對(duì)應(yīng)的處理方法,并調(diào)用查找到的方法,其子類的實(shí)現(xiàn)只需要注冊(cè)這個(gè)visitors的Map,然后實(shí)現(xiàn)注冊(cè)的方法即可;為了增加可擴(kuò)展性,在解析前和解析后分別添加了start、end的插入點(diǎn)。
如在StandardDescriptorProcessor中,注冊(cè)了如下幾個(gè)visitor方法:
context-param => visitContextParam 向WebAppContext添加InitParam信息。
display-name => visitDisplayName 向WebAppContext設(shè)置displayName屬性。
servlet => visitServlet 向ServletHandler中添加一個(gè)新的ServletHolder,并配置其servlet-name、init-param、servlet-class、jsp-file、load-on-startup、security-role-ref、run-as、async-supported、enabled、multipart-config等信息;如果id設(shè)置為jsp,則會(huì)在InitParam中配置scratchdir、classpath參數(shù),以及為Jasper配置com.sun.appserv.jsp.classpath參數(shù),而在WebAppContext中為Jasper配置org.apache.catalina.jsp_classpath屬性;用于注冊(cè)org.apache.jasper.servlet.JspServlet;對(duì)jsp-file,設(shè)置其forcePath為該值。
servlet-mapping=> visitServletMapping 配置ServletHandler中servlet-name對(duì)應(yīng)的ServletMapping信息。
session-config => visitSessionConfig 設(shè)置SessionHandler中SessionManager的一些配置信息。
mime-mapping => visitMimeMapping 設(shè)置WebAppContext中extension到mimeType的映射。
welcome-file-list => visitWelcomeFileList 設(shè)置WebAppContext中的welcomeFiles。
locale-encoding-mapping-list => visitLocaleEncodingList 設(shè)置WebAppContext中l(wèi)ocale到encoding的映射關(guān)系。
error-page => visitErrorPage 設(shè)置ErrorPageErrorHandler中errorCode或exceptionType到location的映射關(guān)系。
taglib => visitTagLib 設(shè)置taglib-uri到taglib-location的映射關(guān)系,即WebAppContext中taglib-uri是taglib-location的alias。
jsp-config => visitJspConfig 將jsp-property-group下url-pattern映射到JspServlet中。
security-constraint => visitSecurityConstraint 向SecurityHandler中添加ConstraintMapping。
login-config => visitLoginConfig 向SecurityHandler中設(shè)置AuthMethod、RealmName屬性,以及對(duì)FORM方法的驗(yàn)證,設(shè)置login、error頁(yè)面的InitParam。
security-role => visitSecurityRole 向SecurityHandler中注冊(cè)定義的role集合。
filter => visitFilter 向ServletHandler注冊(cè)FilterHolder,并配置filter-name、filter-class、init-param、async-supported等信息。
filter-mapping => visitFilterMapping 向ServletHandler注冊(cè)FilterMapping信息。
listenr => visitListener 向WebAppContext注冊(cè)EventListener。
distributable => visitDestributable 設(shè)置WebDescriptor的distributable屬性為true。
在PlusDescriptorProcessor中,首先在其start方法中會(huì)向WebAppContext注冊(cè)InjectionCollection、LifeCycleCallbackCollection、RunAsCollection(該屬性在RunAsAnnotationHandler中使用)屬性,并且注冊(cè)了以下幾個(gè)visitor方法:
env-entry => visitEnvEntry 向InjectionCollection添加Injection實(shí)例,其中jndiName為env-entry-name定義的值,valueClass為env-entry-type定義的類型,而targetClass、targetName為injection-target下的injection-target-class、injection-target-name中定義的值,每個(gè)injection-target生成一個(gè)Injection實(shí)例。同時(shí)將env-entry-value中定義的值綁定到j(luò)ava:com/env/<name>對(duì)應(yīng)的資源中。(Injection實(shí)例也可以使用@Resource注解注冊(cè),并在ResourceAnnotationHandler中解析)
resource-ref => visitResourceRef 向InjectionCollection添加Injection實(shí)例,其中jndiName為res-ref-name,typeClass為res-type,并綁定該引用資源。
resource-env-ref => visitResourceEnvRef 向InjectionCollection添加Injection實(shí)例,其中jndiName為resource-env-ref-name,typeClass為resource-env-ref-type,并綁定該env引用資源。
message-destination-ref => visitMessageDestinationRef 向InjectionCollection添加Injection實(shí)例,其中jndiName為message-destination-ref-name,typeClass為message-destination-type,并綁定該message-destination引用資源。
post-construct => visitPostConstruct 向LifeCycleCallbackCollection注冊(cè)一個(gè)PostConstructCallback,其targetClass由lifecycle-callback-class定義,而method由lifecycle-callback-method定義(該P(yáng)ostConstructCallback也可以使用@PostConstruct的Annotation方式注冊(cè),并在PostConstructAnnotationHandler中解析)。
pre-destroy => visitPreDestroy 向LifeCycleCallbackCollection注冊(cè)PreDestroyCallback,其targetClass由lifecycle-callback-class定義,methodName由lifecycle-callback-method定義(該P(yáng)reDestroyCallback也可以使用@PreDestroy注解注冊(cè),并在PreDestroyAnnotationHandler中解析)。
所有以上注冊(cè)的RunAsCollection、InjectionCollection、LifeCycleCallbackCollection都在PlusDecorator中使用,PlusDecorator類實(shí)現(xiàn)Decorator方法,在所有的decorate實(shí)現(xiàn)方法中,使用RunAsCollection向ServletHolder中注冊(cè)配置的roleName(感覺(jué)這里有bug,應(yīng)該是decorate一個(gè)Servlet而不是ServletHolder);使用InjectionCollection向Servlet、Filter、EventListener注入JNDI對(duì)應(yīng)的值;使用LifeCycleCallbackCollection調(diào)用所有注冊(cè)的PostConstruct方法。而在destroyServlet、Filter實(shí)例時(shí),使用LifeCycleCallbackCollection調(diào)用素有注冊(cè)的PreDestroy方法。