博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入Jetty源码之DescriptorProcessor实现
阅读量:5956 次
发布时间:2019-06-19

本文共 5689 字,大约阅读时间需要 18 分钟。

概述

在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方法。

转载地址:http://vygxx.baihongyu.com/

你可能感兴趣的文章
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>
Python中使用ElementTree解析xml
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
CentOS定时同步系统时间
查看>>
批量删除用户--Shell脚本
查看>>
如何辨别android开发包的安全性
查看>>
Eclipse Java @Override 报错
查看>>
知道双字节码, 如何获取汉字 - 回复 "pinezhou" 的问题
查看>>
linux中cacti和nagios整合
查看>>
Parallels Desktop12推出 新增Parallels Toolbox
查看>>
Python高效编程技巧
查看>>
Kafka服务端脚本详解(1)一topics
查看>>
js中var self=this的解释
查看>>
面试题
查看>>
Facebook 接入之获取各个配置参数
查看>>