深入Jetty源码之XmlConfiguration实现

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介:

概述

XmlConfiguration是Jetty中用来实现使用XML文件配置WebAppContext实例的框架,事实上,他可以用来配置任何的Object类似Digester可以将一个XML配置文件直接实例化成一个类实例,XmlConfiguration可以使用一个XML文件初始化一个Object实例,它支持属性设置、方法调用、新建新实例等。

XmlConfiguration实现

在XmlConfiguration的实现中,可以使用URL、configuration字符串、InputStream作为构造函数传入XmlConfiguration中,在XmlConfiguration的构造函数初始化时,它初始化XmlParser实例,使用XmlParser对XML文件进行解析成一个Node树,并将该树的根节点赋值给config字段;在初始化config字段的同时初始化processor字段,processor字段是ConfigurationProcessor类型,他用于解析XmlParser解析出的Node树的处理类,如果根节点的Tag是Configure,则processor使用Jetty中的默认实现:JettyXmlConfiguration类,否则使用ServiceLoader查找到的ConfigurationProcessorFactory实例,并调用其getConfigurationProcessor方法,传入dtd和tag作为参数,直到找到一个非null的ConfigurationProcessor;在创建出ConfigurationProcessor实例后,首先调用其init方法,在JettyXmlConfiguration类的实现中,init方法只是将传入的参数保存:Node树的config实例、以及两个idMap、propertyMap实例用于传递参数,其中idMap用于保存解析过程中所有id属性对应的实例,也可以用它来传递XML文件用于配置的实例以及其他ref引用的实例,而propertyMap用于定义一些XML文件中用到的属性对应的值。

 

可以使用带Object实例的参数或不带参数两种方式调用configure方法,带参数表示将XML中内容配置实例中的属性,不带参数则先在内部创建class属性指定的类实例,然后使用XML的内容配置该新创建的实例的属性,如果根元素定义了id属性,则可以设置要配置的实例是idMap中该id值对应的实例。

 

在configure方法的真正实现中,它遍历根节点的所有子节点,判断tag值(在这个过程中对任何有id定义的元素,将该id属性的值做为key,该元素对应的实例保存在idMap中):
Set => 用于设置name属性指定的set方法或字段的值,在查找方法中会有各种尝试:1. 尝试当前值实例作为参数的set方法;2. 使用Class实例的TYPE字段作为参数类型的set方法;3. 尝试查找public类型的字段;4. 尝试所有只有一个参数的对应的set方法;5. 尝试是否可以将其转换成Set或数组类型的参数;6. 尝试装箱后的参数。

Put => 要使用该方法,配置类型必须继承自Map接口,使用name属性作为key,获取其值实例,调用put方法。

Call => 指定class属性表示调用其静态方法;读取所有的Arg子节点(Arg节点必须紧跟Call节点),并且解析这些Arg的值类型,name属性指定方法名,在返回后如果其他节点定义,则使用它们配置返回的实例。

Get => 使用name属性指定的get无参数方法,如果没有找到get方法,则从name属性指定的字段中获取值,如果还有子元素,则对返回的实例进行配置。

New => 创建一个class指定的类实例,可以使用Arg指定构造函数参数。如果有除了Arg以外的节点定义,则使用它们对新创建的实例配置。

Array => 创建数组实例,type指定数组类型,支持以下列举的所有的值类型,使用Item指定它的元素。

Ref => 为传入的ref引用实例配置。

Property => 从传入的propertyMap中获取值,可以指定default属性。可以通过定义子元素继续配置返回的值。
Map => 创建新的Map实例,使用Entry/Item, Item指定key、value的值。
对于所有值类型,可以指定其type属性,Jetty默认支持的类型有String、java.lang.String、URL、java.net.URL、InetAddress、java.net.InetAddress、boolean、byte、char、double、float、int、long、short、void、java.lang.Boolean.TYPE、java.lang.Byte.TYPE、java.lang.Character.TYPE、java.lang.Double.TYPE、java.lang.Float.TYPE、java.lang.Integer.TYPE、java.lang.Long.TYPE、java.lang.Short.TYPE、java.lang.Void.TPPE、Boolean、Byte、Character、Double、Float、Integer、Long、Short、null、string等。另外值类型还可以使用Call、Get、New、Ref、Array、Map、Property、SystemProperty定义。其中SystemProperty可以定义name和default属性用于表示prop名和default的值。ref引用必须先定义,因而这里无法处理循环引用的问题。

使用

可以使用XmlConfiguration,给定一个或多个Properties、XML文件参数,在Command Line中直接启动Jetty服务器。

XmlConfiguration也可以用于EnvConfiguration中,用于进一步配置WebAppContext,可以手动设置jettyEnvXmlUrl属性,或默认使用WEB-INF/jetty-env.xml文件。

XmlConfiguration还用于JettyWebXmlConfiguration,他默认查找WEB-INF目录下的jetty8-web.xml、jetty-web.xml、web-jetty.xml作为配置文件对WebAppContext做进一步的配置。

附录
XmlConfiguration支持的XML文件格式使用configure_6_0.dtd文件定义:

<? xml version="1.0" encoding="ISO-8859-1" ?>

<!--
This is the document type descriptor for the
org.eclipse.XmlConfiguration class.  It allows a java object to be
configured by with a sequence of Set, Put and Call elements.  These tags are
mapped to methods on the object to be configured as follows:

  <Set  name="Test">value</Set>              ==  obj.setTest("value");
  <Put  name="Test">value</Put>              ==  obj.put("Test","value");
  <Call name="test"><Arg>value</Arg></Call>  ==  obj.test("value");

Values themselves may be configured objects that are created with the
<New> tag or returned from a <Call> tag.

Values are matched to arguments on a best effort approach, but types
my be specified if a match is not achieved.

-->

<! ENTITY % CONFIG "Set|Get|Put|Call|New|Ref|Array|Map|Property" >
<! ENTITY % VALUE "#PCDATA|Get|Call|New|Ref|Array|Map|SystemProperty|Property" >

<! ENTITY % TYPEATTR "type CDATA #IMPLIED "  >  <!--  String|Character|Short|Byte|Integer|Long|Boolean|Float|Double|char|short|byte|int|long|boolean|float|double|URL|InetAddress|InetAddrPort| #classname  -->
<! ENTITY % IMPLIEDCLASSATTR "class NMTOKEN #IMPLIED"  >
<! ENTITY % CLASSATTR "class NMTOKEN #REQUIRED"  >
<! ENTITY % NAMEATTR "name NMTOKEN #REQUIRED"  >
<! ENTITY % IMPLIEDNAMEATTR "name NMTOKEN #IMPLIED"  >
<! ENTITY % DEFAULTATTR "default CDATA #IMPLIED"  >
<! ENTITY % IDATTR "id NMTOKEN #IMPLIED"  >
<! ENTITY % REQUIREDIDATTR "id NMTOKEN #REQUIRED"  >


<!--
Configure Element.
This is the root element that specifies the class of object that
can be configured:

    <Configure class="com.acme.MyClass">  </Configure>
-->
<! ELEMENT Configure (%CONFIG;)*  >
<! ATTLIST Configure %IMPLIEDCLASSATTR; %IDATTR;  >


<!--
Set Element.
This element maps to a call to a setter method or field on the current object.
The name and optional type attributes are used to select the setter
method. If the name given is xxx, then a setXxx method is used, or
the xxx field is used of setXxx cannot be found.
A Set element can contain value text and/or the value objects returned
by other elements such as Call, New, SystemProperty, etc.
If no value type is specified, then white
space is trimmed out of the value. If it contains multiple value
elements they are added as strings before being converted to any
specified type.

A Set with a class attribute is treated as a static set method invocation.
-->
<! ELEMENT Set ( %VALUE; )*  >
<! ATTLIST Set %NAMEATTR; %TYPEATTR; %IMPLIEDCLASSATTR;  >


<!--
Get Element.
This element maps to a call to a getter method or field on the current object.
The name attribute is used to select the get method.
If the name given is xxx, then a getXxx method is used, or
the xxx field is used if getXxx cannot be found.
A Get element can contain other elements such as Set, Put, Call, etc.
which act on the object returned by the get call.

A Get with a class attribute is treated as a static get method or field.
-->
<! ELEMENT Get (%CONFIG;)* >
<! ATTLIST Get %NAMEATTR; %IMPLIEDCLASSATTR; %IDATTR;  >


<!--
Put Element.
This element maps to a call to a put method on the current object,
which must implement the Map interface. The name attribute is used
as the put key and the optional type attribute can force the type
of the value.

A Put element can contain value text and/or value elements such as Call,
New, SystemProperty, etc. If no value type is specified, then white
space is trimmed out of the value. If it contains multiple value
elements they are added as strings before being converted to any
specified type.
-->
<! ELEMENT Put ( %VALUE; )*  >
<! ATTLIST Put %NAMEATTR; %TYPEATTR;  >


<!--
Call Element.
This element maps to an arbitrary call to a method on the current object,
The name attribute and Arg elements are used to select the method.

A Call element can contain a sequence of Arg elements followed by
a sequence of other elements such as Set, Put, Call, etc. which act on any object
returned by the original call:

 <Call id="o2" name="test">
   <Arg>value1</Arg>
   <Set name="Test">Value2</Set>
 </Call>

This is equivalent to:

 Object o2 = o1.test("value1");
 o2.setTest("value2");

A Call with a class attribute is treated as a static call.
-->
<! ELEMENT Call (Arg*,(%CONFIG;)*) >
<! ATTLIST Call %NAMEATTR; %IMPLIEDCLASSATTR; %IDATTR; >


<!--
Arg Element.
This element defines a positional argument for the Call element.
The optional type attribute can force the type of the value.

An Arg element can contain value text and/or value elements such as Call,
New, SystemProperty, etc. If no value type is specified, then white
space is trimmed out of the value. If it contains multiple value
elements they are added as strings before being converted to any
specified type.
-->
<! ELEMENT Arg ( %VALUE; )*  >
<! ATTLIST Arg %TYPEATTR; %IMPLIEDNAMEATTR;   >


<!--
New Element.
This element allows the creation of a new object as part of a
value for elements such as Set, Put, Arg, etc. The class attribute determines
the type of the new object and the contained Arg elements
are used to select the constructor for the new object.

A New element can contain a sequence of Arg elements followed by
a sequence of elements such as Set, Put, Call, etc. elements
which act on the new object:

 <New id="o" class="com.acme.MyClass">
   <Arg>value1</Arg>
   <Set name="test">Value2</Set>
 </New>

This is equivalent to:

 Object o = new com.acme.MyClass("value1");
 o.setTest("Value2");
-->
<! ELEMENT New (Arg*,(%CONFIG;)*) >
<! ATTLIST New %CLASSATTR; %IDATTR; >


<!--
Ref Element.
This element allows a previously created object to be referenced by id.
A Ref element can contain a sequence of elements such as Set, Put, Call, etc.
which act on the referenced object:

 <Ref id="myobject">
   <Set name="Test">Value2</Set>
 </New>
-->
<! ELEMENT Ref ((%CONFIG;)*) >
<! ATTLIST Ref %REQUIREDIDATTR; >


<!--
Array Element.
This element allows the creation of a new array as part of a
value of elements such as Set, Put, Arg, etc. The type attribute determines
the type of the new array and the contained Item elements
are used for each element of the array:

 <Array type="java.lang.String">
   <Item>value0</Item>
   <Item><New class="java.lang.String"><Arg>value1</Arg></New></Item>
 </Array>

This is equivalent to:
 String[] a = new String[] { "value0", new String("value1") };
-->
<! ELEMENT Array (Item*) >
<! ATTLIST Array %TYPEATTR; %IDATTR;  >


<!--
Map Element.
This element allows the creation of a new map as part of a
value of elements such as Set, Put, Arg, etc. The type attribute determines
the type of the new array and the contained Item elements
are used for each element of the array:

 <Map>
   <Entry>
     <Item>keyName</Item>
     <Item><New class="java.lang.String"><Arg>value1</Arg></New></Item>
   </Entry>
 </Map>

This is equivalent to:
 Map m = new HashMap();
 m.put("keyName", new String("value1"));
-->
<! ELEMENT Map (Entry*) >
<! ATTLIST Map %IDATTR;  >
<! ELEMENT Entry (Item,Item) >


<!--
Item Element.
This element defines an entry for the Array or Map Entry elements.
The optional type attribute can force the type of the value.

An Item element can contain value text and/or the value object of
elements such as Call, New, SystemProperty, etc. If no value type
is specified, then white space is trimmed out of the value.
If it contains multiple value elements they are added as strings
before being converted to any specified type.
-->
<! ELEMENT Item ( %VALUE; )*  >
<! ATTLIST Item %TYPEATTR; %IDATTR;  >


<!--
System Property Element.
This element allows JVM System properties to be retrieved as
part of the value of elements such as Set, Put, Arg, etc.
The name attribute specifies the property name and the optional
default argument provides a default value.

 <SystemProperty name="Test" default="value" />

This is equivalent to:

 System.getProperty("Test","value");
-->
<! ELEMENT SystemProperty EMPTY >
<! ATTLIST SystemProperty %NAMEATTR; %DEFAULTATTR; %IDATTR; >


<!--
Property Element.
This element allows arbitrary properties to be retrieved by name.
The name attribute specifies the property name and the optional
default argument provides a default value.

A Property element can contain a sequence of elements such as Set, Put, Call, etc.
which act on the retrieved object:

 <Property name="Server">
   <Call id="jdbcIdMgr" name="getAttribute">
     <Arg>jdbcIdMgr</Arg>
   </Call>
 </Property>
-->
<! ELEMENT Property ((%CONFIG;)*) >
<! ATTLIST Property %NAMEATTR; %DEFAULTATTR; %IDATTR; >

一个简单的例子(摘自:http://www.blogjava.net/xylz/archive/2012/04/12/372999.html):

< Configure  id ="Server"  class ="org.eclipse.jetty.server.Server" >
     < Set  name ="ThreadPool" >
       < New  class ="org.eclipse.jetty.util.thread.QueuedThreadPool" >
         < Set  name ="minThreads" >10 </ Set >
         < Set  name ="maxThreads" >200 </ Set >
         < Set  name ="detailedDump" >false </ Set >
       </ New >
     </ Set >
     < Call  name ="addConnector" >
       < Arg >
           < New  class ="org.eclipse.jetty.server.nio.SelectChannelConnector" >
             < Set  name ="host" >< Property  name ="Inside in Jetty.host"   /></ Set >
             < Set  name ="port" >< Property  name ="Inside in Jetty.port"  default ="8080" /></ Set >
             < Set  name ="maxIdleTime" >300000 </ Set >
             < Set  name ="Acceptors" >2 </ Set >
             < Set  name ="statsOn" >false </ Set >
             < Set  name ="confidentialPort" >8443 </ Set >
             < Set  name ="lowResourcesConnections" >20000 </ Set >
             < Set  name ="lowResourcesMaxIdleTime" >5000 </ Set >
           </ New >
       </ Arg >
     </ Call >
     < Set  name ="handler" >
       < New  id ="Handlers"  class ="org.eclipse.jetty.server.handler.HandlerCollection" >
         < Set  name ="handlers" >
          < Array  type ="org.eclipse.jetty.server.Handler" >
            < Item >
              < New  id ="Contexts"  class ="org.eclipse.jetty.server.handler.ContextHandlerCollection" />
            </ Item >
            < Item >
              < New  id ="DefaultHandler"  class ="org.eclipse.jetty.server.handler.DefaultHandler" />
            </ Item >
          </ Array >
         </ Set >
       </ New >
     </ Set >
     < Set  name ="stopAtShutdown" >true </ Set >
     < Set  name ="sendServerVersion" >true </ Set >
     < Set  name ="sendDateHeader" >true </ Set >
     < Set  name ="gracefulShutdown" >1000 </ Set >
     < Set  name ="dumpAfterStart" >false </ Set >
     < Set  name ="dumpBeforeStop" >false </ Set >
</ Configure >

相关文章
|
缓存 分布式计算 API
Spark Netty与Jetty (源码阅读十一)
  spark呢,对Netty API又做了一层封装,那么Netty是什么呢~是个鬼。它基于NIO的服务端客户端框架,具体不再说了,下面开始。   创建了一个线程工厂,生成的线程都给定一个前缀名。      像一般的netty框架一样,创建Netty的EventLoopGroup:      在常用...
1098 0
|
Java Windows Maven
Gradle里配置jetty实现静态资源的热部署
通过Gradle我们可以很方便的使用内置jetty启动我们的web程序,在本地进行调试。但是在使用的过程中,我发现了几个问题,导致本地调试的效率大受影响。 如果使用gradle jettyRun启动jetty服务器后,项目里的静态资源(jsp,html,JavaScript文件)都被锁定了,导致无法实时修改这些静态资源。
1360 0
|
Java Android开发 应用服务中间件
【转载】利用jetty+Eclipse实现超轻量级web开发
之前一直使用maven的jetty插件。今天换种方式。   使用下面介绍的方式你只有一个java project就行. 开发环境更简单,debug也更方便,不需要remote debug的方式,jetty非常快,可以明显提高开发效率。
838 0