`
jinnianshilongnian
  • 浏览: 21499238 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2417753
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3008041
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5638944
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:259797
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597022
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250104
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5858130
Group-logo
跟我学Nginx+Lua开...
浏览量:701773
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:784895
社区版块
存档分类
最新评论

Servlet3.1规范翻译——注解和可插拔性

 
阅读更多

 

注解和可插拔性

本章讨论Servlet 3.0规范定义的注解和使web应用内使用的框架和库能够可插拔的增强。

8.1 注解和可插拔性

web应用中,使用注解的类仅当它们位于WEB-INF/classes目录中,或它们被打包到位于应用的WEB-INF/lib中的jar文件中时它们的注解才将被处理。

 

Web应用部署描述符的web-app元素包含一个新的“metadata-complete”属性。“metadata-complete”属性定义了web描述符是否是完整的,或是否应该在部署时检查jar包中的类文件和web fragments。如果“metadata-complete”设置为“true”,部署工具必须必须忽略存在于应用的类文件中的所有servlet注解和web fragments。如果metadata-complete属性没有指定或设置为“false”,部署工具必须检查应用的类文件的注解,并扫描web fragments

 

以下注解必须被Servlet 3.0兼容的容器支持。

8.1.1 @WebServlet

该注解用于在Web应用中定义Servlet组件。该注解在一个类上指定并包含声明Servlet的元数据。必须指定注解的urlPatternsvalue属性。所有其他属性是可选的默认设置(请参考javadoc获取更多细节)。当注解上唯一属性是url模式时推荐使用value且当也有使用其他属性时使用urlPatterns属性。在同一注解上同时使用value urlPatterns属性是非法的。如果没有指定Servlet名字则默认是全限定类名。被注解的sevlet必须指定至少一个url模式进行部署。如果同一个Servlet类以不同的名字声明在部署描述符中,必须实例化一个新的Servlet实例。如果同一个Servlet类使用定义在4-35页的4.4.1 “编程式添加和配置Servlet 的编程式API添加到ServletContext,使用@WebServlet注解声明的值必须被忽略,必须创建一个指定名字的Servlet的新的实例。

@WebServlet注解的类必须继承javax.servlet.http.HttpServlet类。

下面是如何使用该注解的一个示例。

代码示例8-1 @WebServlet 注解示例

@WebServlet(”/foo”)
public class CalculatorServlet extends HttpServlet{
//...
}

下面是如何使用该注解指定更多的属性的一个示例。

 代码示例 8-2 @WebServlet 注解示例使用其它指定的注解属性

@WebServlet(name=”MyServlet”, urlPatterns={"/foo", "/bar"})
public class SampleUsingAnnotationAttributes extends HttpServlet{
    public void doGet(HttpServletRequest req, HttpServletResponse res) {
    }
}

8.1.2 @WebFilter

该注解用于在Web应用中定义Filter。该注解在一个类上指定且包含声明过滤器的元数据。如果没有指定Filter名字则默认是全限定类名。注解的urlPatterns属性, servletNames 属性 value 属性必须被指定。所有其他属性是可选的默认设置(请参考javadoc获取更多细节)。当注解上唯一属性是url模式时推荐使用value且当也有使用其他属性时使用urlPatterns属性。在同一注解上同时使用value urlPatterns属性是非法的。

@ WebFilter注解的类必须实现javax.servlet.Filter

下面是如何使用该注解的一个示例。

代码示例 8-3  @WebFilter 注解示例
@WebFilter(“/foo”)
public class MyFilter implements Filter {
    public void doFilter(HttpServletRequest req, HttpServletResponse res)  {
    ...
    }
}

8.1.3 @WebInitParam

该注解用于指定必须传递到ServletFilter的任何初始化参数。它是WebServletWebFilter注解的一个属性。

8.1.4 @WebListener

WebListener注解用于注解用来获得特定web应用上下文中的各种操作事件的监听器。@WebListener注解的类必须实现以下接口:

javax.servlet.ServletContextListener

javax.servlet.ServletContextAttributeListener

javax.servlet.ServletRequestListener

javax.servlet.ServletRequestAttributeListener

javax.servlet.http.HttpSessionListener

javax.servlet.http.HttpSessionAttributeListener

 

示例:

@WebListener
public class MyListener implements ServletContextListener{
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext sc = sce.getServletContext();
        sc.addServlet("myServlet", "Sample servlet",  "foo.bar.MyServlet", null, -1);
        sc.addServletMapping("myServlet", new String[] { "/urlpattern/*" });
    }
}

8.1.5 @MultipartConfig

该注解,当指定在Servlet上时,表示请求期望是mime/multipart类型。相应servletHttpServletRequest对象必须使用getPartsgetPart方法遍历各个mime附件以获取mime附件。javax.servlet.annotation.MultipartConfiglocation属性和<multipart-config><location>元素被解析为一个绝对路径且默认为javax.servlet.context.tempdir。如果指定了相对地址,它将是相对于tempdir位置。绝对路径与相对地址的测试必须使用java.io.File.isAbsolute

8.1.6 其他注解/惯例

除了这些注解,定义在第15-18315.5节的“注解和资源注入”将继续工作在这些新注解上下文中。

 

默认情况下,所有应用将有index.htm(l)index.jspwelcome-file-list列表中。该描述符可以用来覆盖这些默认设置。

 

当使用注解时,从WEB-INF/classesWEB-INF/lib中的不同框架jar/类加载监听器、Servlet的顺序是没有指定的。如果顺序是很重要的,那么请看web.xml模块部分和后面的web.xmlweb-fragment.xml顺序部分。顺序仅能在部署描述符中指定。

 

8.2 可插拔性

8.2.1 web.xml模块

使用上述定义的注解,使得使用web.xml可选。然而,对于覆盖默认值或使用注解设置的值,需要使用部署描述符。如前所述如果web.xml 描述符中的metadata-complete元素设置为true,则在class文件和绑定在jar包中的web-fragments中的注解将不被处理。这意味着,所有应用的元数据通过web.xml描述符指定。

 

为了给开发人员更好的可插拔性和更少的配置,在这个版本(Servlet 3.0)的规范中,我们引入了web模块部署描述符片段(web fragment)的概念。web fragmentweb.xml的部分或全部,可以在一个类库或框架 jar包的META-INF目录指定和包括。在WEB-INF/lib目录中的普通的老的jar文件即使没有web-fragment.xml也可能被认为是一个fragment,任何在它中指定的注解都将按照定义在8.2.3节的规则处理,容器将会取出并按照如下定义的规则进行配置。

 

web fragmentweb应用的一个逻辑分区,以这样一种方式,在应用中使用的框架可以定义所有制品(artifact)而无需要求开发人员在web.xml中编辑或添加信息。它几乎包含web.xml描述符中使用的所有相同元素。不过描述符的顶级元素必须是web-fragment且对应的描述符文件必须被称为web-fragment.xml,相关元素的顺序在web-fragment.xml web.xml也是不同的,请参考定义在第14章的部署描述符一章中对应的web-fragment schema

 

如果框架打包成jar文件,且有部署描述符的形式的元数据信息,那么web-fragment.xml描述符必须在该jar包的META-INF/目录中。

 

如果框架想使用META-INF/web-fragment.xml,以这样一种方式,它扩充了web应用的web.xml,框架必须被绑定到Web应用的WEB-INF/lib目录中。为了使框架中的任何其他类型的资源(例如,类文件)对web应用可用,把框架放置在web应用的classloader委托链的任意位置即可。换句话说,只有绑定到web应用的WEB-INF/lib目录中的JAR文件,但不是那些在类装载委托链中更高的,需要扫描其web-fragment.xml

 

在部署期间,容器负责扫描上面指定的位置和发现web-fragment.xml并处理它们。存在于当前的单个web.xml的名字唯一性的要求,也同样适用于一组web.xml和所有能适用的web-fragment.xml文件。

 

如下是库或框架可以包括什么的例子。

<web-fragment>
  <servlet>
    <servlet-name>welcome</servlet-name>
    <servlet-class>
      WelcomeServlet
    </servlet-class>
  </servlet>
  <listener>
    <listener-class>   
      RequestListener
   </listener-class>
  </listener>
</web-fragment>

 

以上的web-fragment.xml将被包括在框架的jar文件的META-INF /目录。web-fragment.xml配置和应该应用的注解的顺序是未定义的。如果顺序对于某一应用是很重要的方面,请参考下面如何实现所需的顺序定义的规则。

8.2.2 web.xml和web-fragment.xml顺序

由于规范允许应用配置由多个配置文件组成(web.xml web-fragment.xml)的资源,从应用中多个不同位置发现和加载,顺序问题必须被解决。本节详述了配置资源的作者如何声明他们制品(artifact)的顺序要求。

 

web-fragment.xml可以有一个javaee:java-identifierType类型的顶级<name>元素,且在一个web-fragment.xml中仅能有一个<name>元素。如果存在一个<name>元素,它必须考虑用于artifact顺序(除非出现重复名异常,如上文所述)。

 

两种情况必须被考虑,以允许应用程序配置资源来表达它们的顺序配置。

 

1. 绝对顺序:在web.xml中的<absolute-ordering>元素。在一个web.xml中仅能有一个<absolute-ordering>元素。

a. 在这种情况下,第二种情况处理的顺序配置必须被忽略。

b. web.xmlWEB-INF/classes 必须在列在absolute-ordering元素中的所有web-fragment之前处理。

c. <absolute-ordering>的任何直接子<name>元素必须被解释为在这些被指定的web-fragment中表示绝对顺序,不管它存不存在,必须被处理。

d. <absolute-ordering>可以包含零个或一个<others />元素。下面描述此元素必需的功能。如果<absolute-ordering>元素没有包含<others/>元素,没有在<name />明确提到的web-fragment必须被忽略。不会扫描被排除的jar包中的注解ServletFilterListener。然而,如果是被排除的jar包中的servletfilterlistener,其列在web.xml或非排除的web-fragment.xml中,那么它的注解将使用除非另外使用metadata-complete排除。

在排除的jar包的TLD 文件中发现的ServletContextListener不能使用编程式API配置FilterServlet,任何试图这样做将导致IllegalStateException。如果发现的ServletContainerInitializer是从一个被排除的jar包中装载的,它将被忽略。不扫描被排除的jar包中的任何ServletContainerInitializer处理的类。

e. 重复名字异常:如果,当遍历<absolute-ordering>子元素,遇到多个子元素具有相同<name>元素,只需考虑首次出现的。

 

2. 相对顺序:在web-fragment.xml中的<ordering>元素,一个web-fragment.xml只能有一个<ordering>元素。

a. web-fragment.xml 可以有一个<ordering>元素。如果是这样,该元素必须包含零个或一个<before> 元素和零个或一个<after>元素。这些元素的含义在下面进行说明。

b. web.xmlWEB-INF/classes 必须在列在ordering元素中的所有web-fragment之前处理。

c. 重复命名异常:如果,当遍历web-fragments,遇到多个成员具有相同<name>元素,应用必须记录包含帮助解决这个问题的提供有用信息的错误消息,且部署必须失败。例如,一种解决该问题的办法是用户使用绝对顺序,在这种情况下相对顺序被忽略。

d. 思考这个简短的但具说明下的例子。3web-fragment -作为应用一部分的MyFragment1 MyFragment2 MyFragment3,也包括一个web.xml

 

web-fragment.xml
<web-fragment>
  <name>MyFragment1</name>
  <ordering><after><name>MyFragment2</name></after></ordering>
  ...
</web-fragment>
web-fragment.xml
<web-fragment>
  <name>MyFragment2</name>
  ..
</web-fragment>
web-fragment.xml
<web-fragment>
  <name>MyFragment3</name>
  <ordering><before><others/></before></ordering>
  ..
</web-fragment> 
web.xml
<web-app>
  ...
</web-app>

在该示例中,处理顺序将是:

web.xml

MyFragment3

MyFragment2

MyFragment1

 

前面的示例说明了一些,但不是全部,以下是全部原则。

<before> 意味着文档必须被安排在指定在嵌套<name>元素的name匹配的文档之前。

<after> 意味着文档必须被安排在指定在嵌套<name>元素的name匹配的文档之后。

<before> <after>可以包括特殊的<others/>元素零次或一次,或直接包括在<absolute-ordering>元素中零次或一次。<others/>元素必须作如下处理。

如果<before>元素包含一个嵌套的<others/>,该文档将被移动有序的文档列表开头。如果有多个文指定<before><others/>,则它们将都在有序的文档列表开头,但该组文档的顺序是未指定的。

如果<after>元素包含一个嵌套的<others/>,该文档将被移动有序的文档列表末尾。如果有多个文指定<after><others/>,则它们将都在有序的文档列表末尾,但该组文档的顺序是未指定的。

在一个的<before><after>元素内,如果存在一个<others/> 元素,但在它的父元素内<name>元素不是唯一的,父元素内的其他元素必须按照顺序处理。

如果<others/>直接出现在<absolute-ordering>内,runtime必须确保任何web-fragment未明确指定在<absolute-ordering>部分的以处理的顺序包括在这一点上。

如果web-fragment.xml 文件没有<ordering>web.xml 没有<absolute-ordering>元素,则artifact被假定没有任何顺序依赖。

如果runtime发现循环引用,必须记录提供有用信息的消息,应用必须部署失败。此外, 用户采取的一系列动作可能是在web.xml中使用绝对顺序。

之前的示例可以被扩展以说明当web.xml包含顺序部分的情况。

web.xml
<web-app>
<absolute-ordering>
    <name>MyFragment3</name>
    <name>MyFragment2</name>
  </absolute-ordering>
  ...
</web-app>

在该示例中,各种元素的顺序将是:

 

web.xml

MyFragment3

MyFragment2

 

下面包括了一些额外的示例场景。所有这些适用于相对顺序且不是绝对顺序。

Document A

<after>
  <others/>
  <name>
   C
  </name>
</after>

Document B

<before>
  <others/>
</before> 

Document C

<after>
  <others/>
</after>

 

Document D 没有指定顺序

Document E 没有指定顺序

Document F

<before>
  <others/>
  <name>
   B
  </name>
</before> 

产生的解析顺序:

web.xml, F, B, D, E, C, A

 

Document <no id>

<after>
  <others/>
</after>
<before>
  <name>
    C
  </name>
</before> 

Document B

<before>
  <others/>
</before> 

Document C:没有指定顺序

Document D

<after>
  <others/>
</after> 

Document E

<before>
  <others/>
</before> 

Document F:没有指定顺序

 

产生的解析顺序可能是下列之一:

B, E, F, <no id>, C, D

B, E, F, <no id>, D, C

E, B, F, <no id>, C, D

E, B, F, <no id>, D, C

E, B, F, D, <no id>, C

B, E, F, D, <no id>, C

 

Document A

<after>
  <name>
    B 
  </name>
</after>

 

Document B:没有指定顺序

Document C

<before>
  <others/>
</before> 

Document D: 没有指定顺序

 

产生的解析顺序 C, B, D, A解析的顺序也可能是 C, D, B, A C, B, A, D 

8.2.3 装配web.xml、web-fragment.xml描述符和注解

如果对于一个应用ListenerServletFilter的调用顺序是很重要的,那么必须使用部署描述符。同样,如果有必要,可以使用上面定义的顺序元素。如上所述,当时有注解定义ListenerServletFilter,它们调用的顺序是未指定的。下面是用于装配应用程序的最终部署描述符的一组规则:

1. 如果有关的ListenerServletFilter的顺序必须指定,那么必须指定在web-fragment.xml web.xml

2. 顺序将依据它们定义在描述符中的顺序,和依赖于web.xml中的absolute-ordering 元素或web-fragment.xml 中的ordering元素,如果存在。

a. 匹配请求的过滤器链的顺序是它们在web.xml中声明的顺序。

b. Servlet在请求处理时实例化或在部署时立即实例化。在后一种情况,以它们的load-on-startup 元素表示的顺序实例化。

c. 在之前发布的规范,上下文Listener以随机顺序调用。在Servlet3.0Listener以它们在web.xml中声明的顺序调用,如下所示:

i. javax.servlet.ServletContextListener实现的contextInitialized方法以声明时顺序调用,contextDestroyed 以相反顺序调用。

ii. javax.servlet.ServletRequestListener 实现的requestInitialized 以声明时顺序调用,requestDestroyed 方法以相反顺序调用。

iii. javax.servlet.http.HttpSessionListener 实现的sessionCreated方法以声明时顺序调用,sessionDestroyed 方法以相反顺序调用。

iv. 其他任何Listener接口的调用顺序是未指定的。

3. 如果在web.xml使用enabled元素禁用引入的servlet,那么该servlet将不可以指定url-pattern

4. 当在web.xmlweb-fragment.xml 注解之间解析发生冲突时web应用的web.xml具有最高优先级。

5. 如果没有在描述符中指定metadata-complete 或在部署描述符中设置为false,通过组合出现在注解和描述符中的metadata导出有效的metadata。合并的规则具体如下:

a. web fragment中的配置设置用于扩充那些已指定在主web.xml的配置设置,使用这种方式就好像它们指定在同一个web.xml

b. 添加到主web.xmlweb fragment中的配置设置的顺序由8-70页的8.2.2节“web.xmlweb-fragment.xml顺序”指定。

c. 当主web.xmlmetadata-complete 属性设置为true,被认为是完整的且在部署时不会扫描注解和fragment。如果有absolute-orderingordering元素将被忽略。当设置fragment上的为true时,metadata-complete属性仅适用于在特定的jar包中扫描注解。

d. 除非metadata-complete 设置为true,否则web fragment被合并到主web.xml。合并发生在相关fragment的注解处理之后。

e. 当使用web fragment扩充web.xml时以下被认为配置冲突:

i. 多个<init-param>元素使用相同的<param-name>但不同的<param-value>

ii. 多个<mime-mapping>元素使用相同的<extension>但不同的<mime-type>

f. 上面的配置冲突被解析为如下:

i. 在主web.xmlweb fragment之间的配置冲突被解析为在web.xml的配置具有高优先级。

ii. 在两个web fragment之间的配置冲突,冲突的中心元素没有出现在主web.xml,将导致一个错误。必须记录一个有用的消息,且应用必须部署失败。

g. 上面的冲突被解析后,这些额外的规则适用:

i. 可以在多个web-frament中声明任意多次元素并生成到web.xml。比如,<context-param>元素可以以不同的名字添加。

ii. 如果指定在web.xml中的覆盖了指定在web-fragment中的同名的值,则可以声明任意多次元素。

iii. 如果是最少出现零次且最多出现一次的元素存在于web fragment,且没有在主web.xml中,则主web.xml继承web fragment的设置。如果元素出现在主web.xmlweb fragment,则主web.xml的配置设置具有高优先级。例如,如果在主web.xmlweb fragment中都声明了相同的servlet,且声明在web fragment中的servlet指定了<load-on-startup>元素,且没在主web.xml指定,则web fragment<load-on-startup>元素将被使用并合并到web.xml

iv. 如果是最少出现零次且最多出现一次的元素指定在两个web fragment,且没有出现在主web.xml,则认为是错误的。例如,如果两个web fragment声明了相同的Servlet,但具有不同的<load-on-startup>元素,且相同的Servlet也声明在主web.xml,但没有<load-on-startup>,则必须报告一个错误。

v. <welcome-file>声明是可添加的。

vi. 具有相同<servlet-name><servlet-mapping>元素可以添加到多个web-fragment。在web.xml中指定的<servlet-mapping>覆盖在web-fragment中指定的同名的<servlet-name><servlet-mapping>

vii. 具有相同<filter-name><filter-mapping>元素可以添加到多个web-fragment。在web.xml中指定的<filter-mapping>覆盖在web-fragment中指定的同名的<filter-name><filter-mapping>

viii. 具有相同<listener-class>的多个<listener>元素被当作一个<listener>声明。

ix. 合并产生的web.xml被认为是<distributable>,仅当所有它的web fragment也被标记为<distributable>

x. web fragment的顶级<icon>和它的孩子元素,<display-name>,和<description>元素被忽略。

xi. jsp-property-group是可添加的。当绑定静态资源到jar包的META-INF/resources目录,推荐jsp-config元素使用url-pattern,反对使用extension映射。此外,如果存在一个fragmentJSP资源,则应该在一个与fragment同名的子目录中。这有助于防止一个web-fragmentjsp-property-group受到来自应用的主docroot中的JSP的影响和受到来自一个fragmentMETA-INF/resourcesJSP的影响。

h. 对于所有资源引用元素 (env-entry, ejb-ref, ejb-local-ref, service-ref, resource-ref, resource-env-ref, message-destination-ref, persistence-context-ref and persistence-unit-ref) 如下规则适用:

i. 如果任意资源引用元素出现在web fragment,主web.xml继承web fragment的值。 如果该元素同时出现在主web.xmlweb fragment,使用相同的名字,web.xml具有高优先级。所有fragment的子元素除下面指定的injection-target被合并到主web.xml。例如,如果主web.xmlweb fragment都使用相同的<resource-ref-name>声明一个<resource-ref>,将使用web.xml中的<resource-ref>且不会合并fragment中的任意子元素除下面声明的<injection-target>

ii. 如果资源引用元素指定在两个fragment,当没有指定在主web.xml中,且资源引用元素的所有属性和子元素都是一样的,资源引用将被合并到主web.xml。如果使用相同名字在两个fragment中指定资源引用元素,且没有在web.xml中指定,属性和子元素是不一样的,那么被认为是错误的。错误必须被报告且应用必须部署失败。例如,如果两个web fragment使用相同的<resource-ref-name>声明了<resource-ref>但类型一个指定为javax.sql.DataSource另一个指定为JavaMail,这是错误的且应用必须部署失败。

iii. 对于在fragment中使用相同名称的<injection-target> 的资源引用元素将被合并到主web.xml

i. 除了上面定义的web-fragment.xml的合并规则之外,下面的规则适用于使用资源引用注解(@Resource, @Resources, @EJB, @EJBs, @WebServiceRef, @WebServiceRefs, @PersistenceContext, @PersistenceContexts,@PersistenceUnit, and @PersistenceUnits)

 

如果资源引用注解应用到类上,这等价于定义了一个资源,但是这不等价于定义一个injection-target。在这种情况下上述规则适用于injection-target元素。

 

如果在字段上使用资源引用注解,这等价于在web.xml定义injection-target元素。但是如果在描述符中没有injection-target元素,那么fragment中的injection-target仍将被合并到上面定义的web.xml

 

如果从另一方面来说,在主web.xml中有一个injection-target并同时有一个同资源名的资源引用注解,那么这被认为是对资源引用注解的覆盖。在这种情况下,由于在描述符中指定了一个injection-target,上述定义的规则将适用于除了覆盖的资源引用注解。

j. 如果在两个fragment中指定了data-source元素,而没有出现在主web.xml,且data-source元素的所有属性和子元素都是一样的,data-source将被合并到主web.xml。如果在两个fragment中指定同名的data-source元素,而没有出现在主web.xml且两个fragment的属性和子元素不是一样的,这被认为是错误的。在这种情况下,必须报告一个错误且引用必须部署失败。

 

下面是一些示例,展示了在不同情况下的结果。

 

代码示例8-4

web.xml – 没有 resource-ref 定义

 

Fragment 1

web-fragment.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
    <injection-target>
       <injection-target-class>
            com.foo.Bar.class
       </injection-target-class>
        <injection-target-name>
                baz
        </injection-target-name>
   </injection-target>
</resource-ref>  

有效的metadata将是 

<resource-ref>
    <resource-ref-name="foo">
        ....
         <injection-target>
       <injection-target-class>
            com.foo.Bar.class
       </injection-target-class>
        <injection-target-name>
                baz
        </injection-target-name>
   </injection-target>
</resource-ref> 

  

代码示例8-5

 

web.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
</resource-ref>  

Fragment 1

web-fragment.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
    <injection-target>
       <injection-target-class>
            com.foo.Bar.class
       </injection-target-class>
        <injection-target-name>
                baz
        </injection-target-name>
   </injection-target>
</resource-ref>

 

Fragment 2

web-fragment.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
    <injection-target>
       <injection-target-class>
            com.foo.Bar2.class
       </injection-target-class>
        <injection-target-name>
                baz2
        </injection-target-name>
   </injection-target>
</resource-ref> 

有效的metadata将是

<resource-ref>
    <resource-ref-name="foo">
        ....
<injection-target>
       <injection-target-class>
            com.foo.Bar.class
       </injection-target-class>
        <injection-target-name>
                baz
        </injection-target-name>
   </injection-target>
         <injection-target>
       <injection-target-class>
            com.foo.Bar2.class
       </injection-target-class>
        <injection-target-name>
                baz2
        </injection-target-name>
   </injection-target>
</resource-ref> 

  

代码示例8-6

web.xml

<resource-ref>
    <resource-ref-name="foo">
       <injection-target>
       <injection-target-class>
            com.foo.Bar3.class
       </injection-target-class>
        <injection-target-name>
                baz3
        </injection-target-name>
    ...
</resource-ref> 

Fragment 1

web-fragment.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
    <injection-target>
       <injection-target-class>
            com.foo.Bar.class
       </injection-target-class>
        <injection-target-name>
                baz
        </injection-target-name>
   </injection-target>
</resource-ref> 

 

Fragment 2

web-fragment.xml

<resource-ref>
    <resource-ref-name="foo">
    ...
    <injection-target>
       <injection-target-class>
            com.foo.Bar2.class
       </injection-target-class>
        <injection-target-name>
                baz2
        </injection-target-name>
   </injection-target>
</resource-ref> 

有效的metadata将是

<resource-ref>
    <resource-ref-name="foo">
       <injection-target>
       <injection-target-class>
            com.foo.Bar3.class
       </injection-target-class>
        <injection-target-name>
                baz3
        </injection-target-name>
        <injection-target-class>
            com.foo.Bar.class
        </injection-target-class>
        <injection-target-name>
            baz
        </injection-target-name>
        <injection-target-class>
            com.foo.Bar2.class
        </injection-target-class>
        <injection-target-name>
            baz2
        </injection-target-name>
        </injection-target>
        ...
</resource-ref> 

 

Fragment12<injection-target>将被合并到主web.xml

 

k. 如果主web.xml没有指定任何<post-construct>元素,且web-fragment中也指定了<post-construct> ,那么fragment中的<post-construct>将被合并到主web.xml。不过如果在主web.xml中至少指定一个<post-construct>元素,那么fragment中的<post-construct>将不被合并。由web.xml的作者负责确保<post-construct>列表是完成的。

l. 如果主web.xml没有指定任何<pre-destroy>元素,且web-fragment中也指定了<pre-destroy>,那么fragment中的<pre-destroy>元素将被合并到主web.xml。不过如果在主web.xml中至少指定一个<pre-destroy>元素,那么fragment中的<pre-destroy>将不被合并。由web.xml的作者负责确保<pre-destroy>列表是完成的。

m. 在处理完web-fragment.xml之后,在处理下一个fragment之前相应fragment的注解被处理以完成有效的metadata。以下规则用于处理注解:

n. 通过注解指定的metadata,尚未存在于描述符中,将被用来扩充有效的描述符。

i. 指定在主web.xmlweb fragment中的配置比通过注解指定的配置具有更高优先级。

ii. 使用@WebServlet 注解定义Servlet,要使用描述符覆盖其值,描述符中的servlet名字必须匹配使用注解指定的servlet名字(明确指定或如果注解没有指定则是默认名字)。

iii. 使用注解定义的ServletFilter初始化参数,如果描述符中的初始化参数的名字完全匹配指定在注解中的名字,则将被描述符中的覆盖。初始化参数在注解和描述符之间是可添加的。

iv. url-pattern,当以给定servlet名字指定在描述符中时,将覆盖注解指定的url pattern

v. 使用@WebFilter 注解定义的Filter,要使用描述符覆盖其值,描述符中的Filter名字必须匹配使用注解指定的Filter名字(明确指定或如果注解没有指定则是默认名字)。

vi. Filter应用的url-pattern,当以给定Filter名字指定在描述符中时,将覆盖注解指定的url pattern

vii. Filter应用的DispatcherType,当以给定Filter名字指定在描述符中时,将覆盖注解指定的DispatcherType

viii. 下面的例子演示了上面的一些规则:

 

 

使用注解声明Servlet和在打包到的相应web.xml描述符中声明Servlet

@WebServlet(urlPatterns=”/MyPattern”, initParams={@WebInitParam(name="ccc", value="333")})
public class com.acme.Foo extends HttpServlet {
 ...
} 

web.xml

<servlet>
   <servlet-class>com.acme.Foo</servlet-class>
   <servlet-name>Foo</servlet-name>
   <init-param>
     <param-name>aaa</param-name>
     <param-value>111</param-value>
   </init-param>
</servlet>
<servlet>
   <servlet-class>com.acme.Foo</servlet-class>
   <servlet-name>Fum</servlet-name>
   <init-param>
     <param-name>bbb</param-name>
     <param-value>222</param-value>
   </init-param>
</servlet>
<servlet-mapping>
   <servlet-name>Foo</servlet-name>
   <url-pattern>/foo/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
   <servlet-name>Fum</servlet-name>
   <url-pattern>/fum/*</url-pattern>
</servlet-mapping>

 

因为使用注解声明的Servlet名字不匹配在web.xml中声明的servlet名字,在web.xml中除了其他的声明外,注解指定一个新的servlet声明,相当于:

<servlet>
   <servlet-class>com.acme.Foo</servlet-class>
   <servlet-name>com.acme.Foo</servlet-name>
   <init-param>
     <param-name>ccc</param-name>
     <param-value>333</param-name>
</servlet>

 

如果上面的web.xml被替换为如下:

<servlet>
   <servlet-class>com.acme.Foo</servlet-class>
   <servlet-name>com.acme.Foo</servlet-name>
   <init-param>
     <param-name>aaa</param-name>
     <param-value>111</param-value>
   </init-param>
 </servlet>
 <servlet-mapping>
   <servlet-name>com.acme.Foo</servlet-name>
   <url-pattern>/foo/*</url-pattern>
 </servlet-mapping> 

那么有效的描述符将等价于:

<servlet>
   <servlet-class>com.acme.Foo</servlet-class>
   <servlet-name>com.acme.Foo</servlet-name>
   <init-param>
     <param-name>aaa</param-name>
     <param-value>111</param-value>
   </init-param>
<init-param>
     <param-name>ccc</param-name>
     <param-value>333</param-value>
   </init-param>
 </servlet>
 <servlet-mapping>
   <servlet-name>com.acme.Foo</servlet-name>
   <url-pattern>/foo/*</url-pattern>
 </servlet-mapping> 

 

8.2.4 共享库 / 运行时可插拔性

除了支持fragment和使用注解的外,要求之一是我们不仅能plug-in 绑定在WEB-INF/lib下的,也能plugin框架共享副本—包括能plug-in到容器的如建议在web容器之上的JAX-WSJAX-RSJSFServletContainerInitializer允许处理这样的使用情况下,如下所述。

 

在容器/应用启动时,由容器通过jar services API查找一个ServletContainerInitializer实例。框架提供的ServletContainerInitializer实现必须绑定在jar包的META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件,根据jar services API,指定ServletContainerInitializer的实现。

 

ServletContainerInitializer外,我们还有一个注解—HandlesTypes。在ServletContainerInitializer 实现上的HandlesTypes注解用于表示感兴趣的一些类,它们可能指定了HandlesTypesvalue中的注解(类型、方法或自动级别的注解),或者是其类型的超类继承/实现了这些类之一。容器使用HandlesTypes注解决定什么时候调用initializeronStartup方法。当检测一个应用的类看是否它们匹配ServletContainerInitializerHandlesTypes指定的条件时,如果应用的一个或多个可选的JAR包缺失,容器可能遇到类装载问题。由于容器不能决定是否这些类型的类装载失败将阻止应用正常工作,它必须忽略它们,同时也提供一个将记录它们的配置选项。

 

如果ServletContainerInitializer实现没有@HandlesTypes注解,或如果没有匹配任何指定的HandlesType,那么它会为每个应用使用null 值的集合调用一次。这将允许initializer基于应用中可用的资源决定是否需要初始化Servlet/Filter

 

在任何Listener的事件被触发之前,当应用正在启动时,ServletContainerInitializeronStartup方法将被调用。

 

ServletContainerInitializer’sonStartup得到一个类的Set,其或者继承/实现initializer表示感兴趣的类,或者它是使用指定在@HandlesTypes注解中的任意类注解的。

 

下面一个具体的例子展示了这是如何工作的。

 

让我们学习JAX-WS web service 运行时。

 

JAX-WS运行时实现通常不是绑定到每个war包。其实现将绑定一个ServletContainerInitializer的实现(如下所示)且容器将查找使用的services API(绑定在jar包中的META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件,它将指出如下所示的JAXWSServletContainerInitializer)。

@HandlesTypes(WebService.class)
JAXWSServletContainerInitializer implements ServletContainerInitializer  {
    public void onStartup(Set<Class<?>> c, ServletContext ctx)  throws ServletException {
        // 在此,使用JAX-WS 特定的代码来初始化运行库和设置mapping等。
        ServletRegistration reg = ctx.addServlet("JAXWSServlet", "com.sun.webservice.JAXWSServlet");
        reg.addServletMapping("/foo");
    }
}

 

框架的jar包也可能被绑定到war报目录中的WEB-INF/lib目录。如果ServletContainerInitializer被绑定到应用的WEB-INF/lib目录内的一个JAR包中,它的onStartup方法在绑定到的应用启动期间将被仅调用一次。如果,相反,ServletContainerInitialzer被绑定到WEB-INF/lib目录外的一个JAR包中,但仍能被运行时的服务提供商查找机制发现时,每次启动应用时,它的onStartup方法将被调用。

 

ServletContainerInitializer接口的实现将被运行时的服务查找机制或语义上与它等价的容器特定机制发现。在任一种情况,web fragment JAR包的ServletContainerInitializer 服务被排除于一个absolute ordering必须被忽略,这些服务被发现的顺序必须遵照应用的类装载委托模型。

8.3 JSP容器可插拔性

ServletContainerInitializer和编程式注册特性可以在ServletJSP容器之间提供一个清晰的职责分离,通过由Servlet容器只负责解析web.xmlweb-fragment.xml资源,而解析标签库描述符(TLD)资源委托给JSP容器。

 

在此之前,web容器必须扫描TLD资源寻找任何Listener声明。使用Servlet3.0后,该职责可以委托给JSP容器。JSP容器是内嵌到一个Servlet3.0兼容的Servlet容器中,可以提供它自己的ServletContainerInitializer实现,搜索传递到它的onStartup方法的ServletContext参数寻找任何TLD资源,扫描这些资源寻找Listener声明,并向ServletContext注册相关的Listener

 

另外,Servlet3.0之前,JSP容器用于必须扫描应用的部署描述符寻找jsp-config相关的配置。使用Servlet3.0后,Servlet容器必须提供通过ServletContext.getJspConfigDescriptor方法得到应用的web.xmlweb-fragment.xml部署描述符中的任何jsp-config相关的配置。

 

TLD中发现的和编程注册的任何ServletContextListener在它们提供的功能上是有限的。任何试图调用一个在Servlet3.0中加入的ServletContext API方法将导致一个UnsupportedOperationException

 

另外,Servlet3.0兼容的Servlet容器必须提供一个名字为javax.servlet.context.orderedLibsServletContext属性,它的值(java.util.List<java.lang.String>类型)包含了由ServletContext所代表的应用的WEB-INF/lib目录中的JAR文件的名字列表,按照它们的web fragment名字的排序(可能排除如果fragment JAR包已经被排除在absolute-ordering),或者null如果应用没有指定任意绝对或相对顺序。

8.4 处理注解和fragment

Web应用可同时包括注解和web.xml/web-fragment.xml部署描述符。如果没有部署描述符,或有一个但其metadata-complete没有设置为trueweb.xmlweb-fragment和注解如果在应用中使用则必须被处理。下表描述了是否处理注解和web.xmlfragment

 

8-1  注解和web fragment处理要求

部署描述符

metadata-complete

处理注解和web fragment

web.xml 2.5

yes

no

web.xml 2.5

no

yes

web.xml 3.0

yes

no

web.xml 3.0

no

yes

 

 

4
23
分享到:
评论
7 楼 Carvendy许 2017-02-20  
webfilter 怎么设置先后顺序呢?
6 楼 jinnianshilongnian 2012-12-20  
xiangdefei 写道
异步servlet是3.1里面的吧。

3.0里新增的
5 楼 xiangdefei 2012-12-20  
异步servlet是3.1里面的吧。
4 楼 jinnianshilongnian 2012-12-20  
masuweng 写道
还望楼主做个demo贴出来,

有时间尽量写一写    servlet3还是不少好东西
3 楼 masuweng 2012-12-20  
还望楼主做个demo贴出来,
2 楼 jinnianshilongnian 2012-12-20  
MrCrapBag 写道
好文,3.0的要求更加规范了。

不过对我们经常使用的  数据绑定、数据验证、数据格式化  没有任何增强,使用框架还是避免不了。
1 楼 MrCrapBag 2012-12-20  
好文,3.0的要求更加规范了。

相关推荐

    Servlet3.1规范(最终版)

    1. 注解驱动:Servlet3.1增加了对注解的广泛支持,如`@WebServlet`、`@WebFilter`和`@WebListener`,开发者可以直接在类上声明这些注解,减少web.xml配置文件的依赖,提高代码的可读性和维护性。 2. 前缀匹配:`@Web...

    java servlet 3.1规范中文翻译

    此外,Servlet 3.1规范还增强了对JSP容器的可插拔性的支持,允许更加灵活的JSP容器集成。与其它规范的整合方面,Servlet 3.1规范支持与其他Java EE组件如EJB(Enterprise JavaBeans)和JSF(JavaServer Faces)等更...

    Servlet3.1规范(最终版)(中英双版本)

    6. **注解增强**:除了原有的`@WebServlet`,`@WebFilter`和`@WebListener`注解,Servlet 3.1进一步增强了注解的使用,允许开发者通过注解来定义安全约束、初始化参数和错误页面等,减少了XML配置文件的依赖。...

    Servlet3.1规范官方文档(中文版)

    首先,Servlet3.1官方文档是Java™ Servlet规范版本3.1的中文翻译版本。它详细描述了servlet技术规范的各个方面,包括对servlets的定义、生命周期、事件监听、安全性、异步处理等。Servlet3.1规范被包含在JavaEE7...

    servlet 3.1规范

    Servlet 3.1规范是Java Web开发中的一个重要里程碑,它扩展了Servlet 3.0的特性,提供了更多现代化的功能和优化。这份官方原版的PDF文档详细阐述了Servlet API的最新标准,帮助开发者理解和利用这些新特性来构建高效...

    Servlet3.1 规范最终版

    增强的注解支持:Servlet3.1进一步增强了注解的使用,比如可以使用`@MultipartConfig`注解来配置文件上传,`@WebFilter`和`@WebServlet`注解用于声明过滤器和Servlet,这使得无XML部署成为可能,降低了部署复杂性。...

    Servlet3.1规范(最终版)高清-完整-目录

    1. **注解驱动的Servlet配置**:Servlet3.1引入了注解来简化部署描述符(web.xml)的配置,允许开发者直接在Servlet类上使用`@WebServlet`注解,声明Servlet的URL映射、初始化参数等。 2. **异步Servlet处理**:...

    Servlet3.1 规范(最新汉化版本)

    4. **注解增强**:除了Servlet3.0中已有的`@WebServlet`,Servlet3.1进一步增强了注解的使用,如`@WebFilter`和`@WebListener`,可以直接在类上声明过滤器和监听器,减少了XML配置,提升了代码的可读性和维护性。...

    Servlet3.1规范(英文).pdf

    通过对异步处理能力、文件上传功能、配置方式等方面的改进,Servlet 3.1 大大提升了 Web 应用程序的性能和可维护性。此外,与 Java EE 7 规范的一致性确保了 Servlet 技术能够跟上现代 Web 开发的步伐。对于希望利用...

    Servlet3.1规范(中文最终版)

    Servlet3.1规范是Java Web开发中的一个重要里程碑,它在Servlet3.0的基础上引入了许多增强功能,提高了Web应用的性能和可扩展性。这个中文最终版的文档为开发者提供了全面的指南,帮助他们理解并利用这些新特性进行...

    Servlet3.1规范(最终版).pdf

    总之,Servlet3.1规范带来了许多创新和改进,包括异步处理、增强的注解支持、非-blocking I/O、WebSocket支持以及对HTTP/2的兼容。这些特性极大地提升了Java Web开发的灵活性、性能和可维护性,使得开发人员能够构建...

    Servlet3.1规范文档

    在Servlet3.1规范中,它引入了异步处理机制,这允许Web应用在不占用当前Servlet线程的情况下进行长时间运行的处理,从而提高了对客户端请求的响应效率。这一点对于处理耗时较长的任务(如访问数据库、文件系统等)...

    Servlet 3.1 规范(最终版)中英文版.7z

    Servlet 3.1 规范是Java服务器端编程的一个关键组成部分,它定义了Servlet容器如何与Web应用程序交互的标准。此规范的最终版引入了一系列新功能和改进,旨在提高开发效率,增强性能,并提供更灵活的部署选项。以下是...

    Servlet3.1规范中文版

    Servlet3.1规范是Java Servlet技术的一个版本,它在Java EE平台中扮演着重要的角色。Java EE(Java Platform, Enterprise Edition)是一个为开发企业级应用提供的平台,而Servlet是Java EE技术中用于处理Web请求的...

    Servlet3.1规范说明中文版_英文版.rar

    Servlet 3.1 规范是Java服务器端编程的重要组成部分,是Java EE 7标准的一部分。...通过阅读提供的"Servlet 3.1规范说明中文版"和"Servlet3.1规范(最终版)"文档,可以更全面地了解这些概念并应用于实际开发中。

    Web开发中文手册之Servlet3.1规范.zip

    Servlet3.1规范是Java Web开发中的一个重要里程碑,它在Servlet3.0的基础上进行了一系列的增强和优化,为开发者提供了更多的灵活性和效率提升。这份"Web开发中文手册之Servlet3.1规范"无疑是广大Java Web开发者的...

    Servlet3.1规范 中文.zip

    Servlet3.1规范在Servlet 3.0的基础上进行了一系列增强和改进,包括异步处理、注解配置、微容器(Microcontainer)支持等。 1. **异步处理**:Servlet3.1引入了异步Servlet API,使得开发者可以将处理任务放到后台...

    servlet3.1规范

    5. **依赖注入**:Servlet 3.1引入了CDI(Contexts and Dependency Injection)的支持,允许开发者通过注解来注入依赖,如`@Inject`,提升了代码的可测试性和可维护性。 6. **URL路径匹配增强**:Servlet 3.1支持更...

Global site tag (gtag.js) - Google Analytics