Servlet规范之注解与可插拔性

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet规范之注解与可插拔性相关的知识,希望对你有一定的参考价值。

Annotations and pluggability

文章是对 JSR-000340 JavaTM Servlet 3.1 Final Release的Java™ Servlet规范的翻译,尚未校准

文章目录


本章描述了注解和其他增强功能的使用,以实现框架和库的可插拔性,以便在Web应用程序中使用。

注释和可插拔性

在Web应用程序中,使用注解的类只有在位于WEB-INF/classes目录下,或者在应用程序中被打包在位于WEB-INF/lib的jar文件中时,其注解才会得到处理。网络应用程序部署描述符在web-app元素上包含一个新的"metadata-complete"属性。metadata-complete"属性定义了web描述符是否完整,或者jar文件的类文件是否应该在部署时检查注释和web片段。如果 "metadata-complete "被设置为 “true”,部署工具必须忽略任何Servlet注解,这些注解指定了应用和Web片段的类文件中存在的部署信息。如果没有指定元数据完整属性或将其设置为 “false”,部署工具必须检查应用程序的类文件以获得注释,并扫描Web片段。以下是必须由符合Servlet 3.0的Web容器支持的注释。

@WebServlet

该注解用于在Web应用程序中定义一个 "Servlet "组件。这个注解被指定在一个类上,并包含关于被声明的Servlet的元数据。注解中的urlPatternsvalue属性必须存在。所有其他属性都是可选的,有默认设置(更多细节见javadocs)。当注解上唯一的属性是url模式时,建议使用value,当其他属性也被使用时,使用urlPatterns属性。在同一个注解上同时使用valueurlPatterns属性是非法的。如果没有指定 “Servlet”,其默认名称是完全合格的类名称。被注解的Servlet必须至少指定一个要部署的url模式。如果在部署描述符中以不同的名称声明相同的servlet类,则必须实例化该servlet的新实例。如果通过第4.4.1节 “Programmatically adding and configuring Servlets”(第4-35页)中定义的编程API,以不同的名称将相同的Servlet类添加到 “ServletContext"中,通过”@WebServlet"注解声明的属性值必须被忽略,并且必须创建一个具有指定名称的Servlet的新实例。

@WebServlet类注释的类必须扩展javax.servlet.http.HttpServlet类。

下面是一个如何使用这种注释的例子。

CODE EXAMPLE 8-1 @WebServlet Annotation Example

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

下面是一个例子,说明如何使用这个注释,并指定一些更多的属性。

CODE EXAMPLE 8-2 @WebServlet annotation example using other annotation attributes specified

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

@WebFilter

该注解用于在Web应用程序中定义一个 “Filter”。这个注解被指定在一个类上,并包含关于被声明的过滤器的元数据。如果没有指定,"过滤器 "的默认名称是完全合格的类名称。urlPatterns属性、servletNames属性或注释的value属性必须被指定。所有其他属性都是可选的,有默认设置(更多细节见javadocs)。当注解的唯一属性是url模式时,建议使用value,当其他属性也被使用时,建议使用urlPatterns属性。在同一个注解上同时使用value和urlPatterns属性是非法的。

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

下面是一个如何使用这种注释的例子。

CODE EXAMPLE 8-3 @WebFilter annotation example

@WebFilter(/foo”)
public class MyFilter implements Filter 
public void doFilter(HttpServletRequest req, HttpServletResponse res)
    
    ...
    

@WebInitParam

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

@WebListener

WebListener注解用于注解一个监听器,以获取特定Web应用程序上下文的各种操作的事件。用@WebListener注解的类必须实现以下接口之一:

  • javax.servlet.ServletContextListener
  • javax.servlet.ServletContextAttributeListener
  • javax.servlet.ServletRequestListener
  • javax.servlet.ServletRequestAttributeListener
  • javax.servlet.http.HttpSessionListener
  • javax.servlet.http.HttpSessionAttributeListener
  • javax.servlet.http.HttpSessionIdListener

An example:

@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/*");
    

@MultipartConfig

当在一个Servlet上指定这个注解时,表明它所期望的请求是mime/multipart类型。相应Servlet的HttpServletRequest对象必须通过getPartsgetPart方法来提供mime附件,以遍历各种mime附件。javax.servlet.annotation.MultipartConfig<multipart-config><location>元素的location属性被解释为绝对路径,默认为javax.servlet.context.tempdir的值。如果指定了一个相对路径,它将是相对于tempdir的位置。绝对路径与相对路径的测试必须通过java.io.File.isAbsolute来完成。

其他注释/约定

除了这些注解之外,第15-189页的第15.5节 "Annotations and Resource Injection"中定义的所有注解将继续在这些新注解的背景下工作。

默认情况下,所有应用程序都会在 welcome-file-list中包含index.htm(l)index.jsp。该描述符可以用来覆盖这些默认设置。

当使用注解时,从WEB-INF/classesWEB-INF/lib中的各种框架jars/class中加载监听器、Servlets的顺序是没有规定的。如果排序很重要,那么请看下面的web.xml的模块化以及web.xmlweb-fragment.xml的排序部分。顺序可以只在部署描述符中指定。

Pluggability

web.xml web.xml的模块化程度

使用上面定义的注解使web.xml的使用成为可选项。然而,对于覆盖默认值或通过注释设置的值,部署描述符被使用。和以前一样,如果metadata-complete元素在web.xml描述符中被设置为true,那么指定存在于类文件和捆绑在jars中的web-fragments的部署信息的注释将不会被处理。这意味着应用程序的所有元数据都是通过web.xml描述符指定的。

为了提高可插拔性和减少开发人员的配置,我们引入了web模块部署描述符片段(web fragment)的概念。web片段是web.xml的一部分或全部,可以指定并包含在一个库或框架jar的META-INF目录中。在WEB-INF/ lib目录下的一个普通的jar文件,没有web-fragment.xml也被认为是一个片段。其中指定的任何注释将按照 8.2.3 中定义的规则进行处理。容器将按照下面定义的规则拾取和使用配置。

Web 片段是对 Web 应用程序的逻辑划分,其方式是在 Web 应用程序中使用的框架可以定义所有的工件,而不要求开发者在 web.xml 中编辑或添加信息。它几乎可以包括web.xml描述符使用的所有相同元素。然而,描述符的顶层元素必须是web-fragment,相应的描述符文件必须称为web-fragment.xml。web-fragment.xml和web.xml的相关元素的排序也不同,请看第14章部署描述符部分中的web-fragments的相应模式。

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

如果一个框架希望它的META-INF/web-fragment.xml以这样一种方式被尊重,即它增强了Web应用程序的web.xml,那么该框架必须被捆绑在Web应用程序的WEB-INF/lib目录中。为了使框架的任何其他类型的资源(例如,类文件)对Web应用程序可用,只要框架出现在Web应用程序的类加载器委托链的任何地方就可以了。换句话说,只有捆绑在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中的配置和注解的应用顺序是未定义的。如果顺序对一个特定的应用来说是一个重要的方面,请看下面定义的规则,如何实现所需的顺序。

web.xml和web-fragment.xml的排序

由于规范允许应用程序配置资源由多个配置文件(web.xmlweb-fragment.xml)组成,从应用程序的几个不同地方发现和加载,所以必须解决排序的问题。本节规定了配置资源作者如何声明其工件的排序要求。

一个web-fragment.xml可以有一个顶层的<name>元素,类型为javaee:java-identifierType。一个web-fragment.xml中只能有一个<name>元素。如果有一个<name>元素存在,在对工件排序时必须考虑它(除非重复的名字例外,如下所述)。

必须考虑两种情况,以允许应用配置资源表达其排序偏好。

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

    1. 在这种情况下,必须忽略本来由下面情况2处理的排序偏好。
    2. web.xml和 WEB-INF/classes 必须在absolute-ordering元素中列出的任何web-fragments之前被处理。
    3. 任何<name>元素的直接子元素<absolute-ordering>必须被解释为表示那些被命名的web-fragments(可能存在也可能不存在)必须被处理的绝对顺序。
    4. <absolute-ordering>元素可以包含零或一个<others/>元素。这个元素所需的行动在下面描述。如果<absolute-ordering>元素不包含<others/>元素,任何在<name/>元素中没有特别提到的web-fragment都必须被忽略。被排除的罐子不会被扫描出有注释的Servlet、过滤器或监听器。然而,如果被排除的jar中的servlet、过滤器或监听器被列在web.xml或非排除的web-fragment.xml中,那么它的注释将被应用,除非被metadata-complete排除。在被排除的jars的TLD文件中发现的ServletContextListeners不能使用编程API来配置过滤器和servlets。任何试图这样做的行为都会导致 “非法状态异常”(IllegalStateException)。如果一个被发现的ServletContainerInitializer是从被排除的jar加载的,它将被忽略。不管metadata-complete的设置如何,被<absolute-ordering>元素排除的jar不会被扫描,以寻找任何ServletContainerInitializer要处理的类。
    5. 重复名称例外:如果在遍历<absoluteordering>的子节点时,遇到具有相同<name>元素的多个子节点,必须只考虑第一次出现的这种情况。
  2. 相对排序:在web-fragment.xml中的一个<ordering>元素。一个web-fragment.xml中只能有一个<ordering>元素。

    1. 一个 web-fragment.xml可能有一个<ordering>元素。如果是这样,这个元素必须包含零或一个<before>元素和零或一个after>元素。这些元素的含义将在下面解释。
    2. web.xml和WEB-INF/classes必须在ordering元素中列出的任何web-fragments之前被处理。
    3. 重复名称例外:如果在遍历web-fragments时,遇到具有相同<name>元素的多个成员,应用程序必须记录一个信息性的错误信息,包括帮助解决问题的信息,并且必须不能部署。例如,解决这个问题的一个方法是用户使用绝对排序,在这种情况下,相对排序被忽略。
    4. 考虑一下这个简略但能说明问题的例子。3个web-fragments - MyFragment1, MyFragment2MyFragment3是应用程序的一部分,也包括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>元素相符的文件之前。

  • <after>表示文件必须排序在名字与嵌套的<name>元素相匹配的文件之后。

  • 有一个特殊的元素<others/>,它可以在<before><after>元素中包含零次或一次,或者在<absolute-ordering>元素中直接包含零次或一次。<others/>元素必须按以下方式处理。

    • 如果<before>元素包含一个嵌套的<others/>,该文件将被移到排序文件列表的开头。如果有多个文件说明<before><others/>,它们都将在排序文件列表的开头,但在这类文件组中的排序是没有规定的。
    • 如果<after>元素包含一个嵌套的<others/>,该文件将被移到排序文件列表的最后。如果有多个文件需要<after><others/>,它们都将在排序文件列表的末尾,但在这类文件组中的排序是未指定的。
    • 在一个<before><after>元素内,如果有一个<others/>元素存在,但不是其父元素内唯一的<name>元素,在排序过程中必须考虑该父元素内的其他元素。
    • 如果<others/>元素直接出现在<absoluteordering>元素内,运行时必须确保任何未在<absolute-ordering>部分明确命名的网络碎片在该点被包括在处理顺序中。
  • 如果web-fragment.xml文件没有<ordering>,或者web.xml没有<absolute-ordering>元素,则认为工件没有任何排序依赖。

  • 如果运行时发现了循环引用,必须记录一条信息,并且应用程序必须不能部署。同样,用户可以采取的一个行动方案是在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: no ordering

Document E: no ordering

Document F:
<before>
<others/>
<name>
B
</name>
</before>

Resulting parse order: 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: no ordering
Document D:
<after>
<others/>
</after>
Document E:
<before>
<others/>
</before>
Document F: no ordering

Resulting parse order can be one of the following:

  • 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

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

    Document A:
    <after>
    <name>
    B
    </name>
    </after>
    Document B: no ordering
    Document C:
    <before>
    <others/>
    </before>
    Document D: no ordering
    

Resulting parse order: C, B, D, A. The parse order could also be: C, D, B, A or C, B, A, D

从web.xml、web-fragment.xml和注解中组装描述符

如果listeners、servlets、filters的调用顺序对一个应用程序很重要,那么必须使用部署描述符。另外,如果有必要,可以使用上面定义的排序元素。如上所述,当使用注解来定义listeners、servlets、filters时,它们被调用的顺序是未指定的。下面是一组适用于组装应用程序的最终部署描述符的规则。

  1. listeners, servlets, filters的顺序必须在web-fragment.xmlweb.xml中指定。

  2. 排序将基于它们在描述符中定义的顺序和web.xml中的absolute-ordering元素或web-fragment.xml中的排序元素(如果存在)。

    1. 匹配请求的过滤器是按照它们在web.xml中声明的顺序链式的。
    2. Servlet可以在请求处理时被懒惰地初始化,或在部署时被急切地初始化。在后一种情况下,它们是按照它们的 "load-on-startup"元素的顺序来初始化的。
    3. listeners是按照它们在web.xml中声明的顺序来调用的,具体规定如下。
      1. javax.servlet.ServletContextListener的实现在其contextInitialized方法中按其声明的顺序被调用,在其contextDestroyed方法中按相反顺序被调用。
      2. javax.servlet.ServletRequestListener的实现会按照它们被声明的顺序在它们的requestInitialized方法处被调用,并按照相反的顺序在它们的requestDestroyed方法处被调用。
      3. javax.servlet.http.HttpSessionListener的实现会按照它们被声明的顺序在它们的sessionCreated方法中被调用,并按照相反的顺序在它们的sessionDestroyed方法中被调用。
      4. javax.servlet.ServletContextAttributeListenerjavax.servlet.ServletRequestAttributeListenerjavax.servlet.HttpSessionAttributeListener的实现方法在相应的事件被触发时按照声明的顺序被调用。
  3. 如果使用web.xml中引入的enabled元素禁用一个Servlet,那么该Servlet将不能在为该Servlet指定的url-pattern中使用。

  4. 在解决web.xmlweb-fragment.xml和注释之间的冲突时,web应用程序的web.xml具有最高优先权。

  5. 如果描述符中没有指定metadata-complete,或者在部署描述符中设置为false,那么应用程序的有效元数据将通过合并注释和描述符中存在的元数据而得到。合并的规则规定如下:

    1. 在web fragments中的配置设置被用来增加那些在主web.xml中指定的配置,就像它们被指定在同一个web.xml中一样。

    2. 网络片段的配置设置被添加到主web.xml中的配置设置的顺序,如第8.2.2节 “Ordering of web.xml and web-fragment.xm”(第8-72页)中的规定。

    3. metadata-complete属性在主web.xml中设置为true时,被认为是完整的,在部署时不会发生注释和片段的扫描。如果存在absolute-ordering和排序元素,将被忽略。当在一个片段上设置为true'时,metadata-complete’属性只适用于扫描该特定jar中的注释。

    4. 除非metadata-complete被设置为true,否则网络片段将被合并到主web.xml中。合并是在相应片段的注释处理之后进行的。

    5. The following are considered configuration conflicts when augmenting a web.xml with web fragments:

    6. 当用web fragments丰富web.xml配置时,以下被认为是配置冲突:

      1. 多个 init-param 元素具有相同的<param-name>但不同的<param-value>
      2. 多个<mime-mapping>元素具有相同的<extension>但不同的<mime-type>
    7. 上述配置冲突的解决方法如下:

      1. 主web.xml和web片段之间的配置冲突被解决,从而使web.xml中的配置具有优先权。
      2. 两个web片段之间的配置冲突,如果冲突中心的元素不在主web.xml中,将导致一个错误。必须记录一个信息性的消息,并且应用程序必须无法部署。
    8. 在解决了上述冲突之后,还要应用这些额外的规则:

      1. 可以声明任何次数的元素在所产生的web.xml'中的web-fragments’之间是相加的。例如,具有不同的 "参数名称 "的<context-param>元素是相加的。
      2. 可以声明任何次数的元素,如果在web.xml中指定,将覆盖web-fragments中指定的同名值。
      3. 如果一个最小出现次数为0,最大出现次数为1的元素出现在web片段中,而在主web.xml中缺失,主web.xml将继承web片段中的设置。如果该元素同时出现在主web.xml和网络片段中,则以主web.xml中的配置设置为准。例如,如果主web.xml和一个web片段都声明了同一个Servlet,而web片段中的Servlet声明指定了一个<load-on-startup>元素,而主web.xml中没有,那么web片段中的<load-on-startup>元素将在合并的web.xml中使用。
      4. 如果一个最小出现次数为0,最大出现次数为1的元素,在两个网络片段中被指定为不同的元素,而在主web.xml中却没有,这将被视为一个错误。例如,如果两个web-fragments声明了相同的servlet,但有不同的<load-on-startup>元素,而在主web.xml中也声明了相同的servlet,但没有任何<load-on-startup>,那么必须报告一个错误。
      5. <welcome-file>的声明是附加的。
      6. <servlet-mapping>元素具有相同的<servlet-name>,在不同的web-fragments中是相加的。在 "web.xml "中指定的<servlet-mapping>将覆盖在具有相同<servlet-name>的web-fragments中的值。
      7. 具有相同<filter-name><filter-mapping>元素在网络片段中是相加的。在 "web.xml “中指定的<filter-mapping>将覆盖在具有相同”<filter-name>"的web-fragments中指定的值。
      8. 具有相同<listener-class>的多个<listener>元素被视为一个<listener>声明
      9. 合并产生的web.xml只有在其所有网络片段也被标记为<distributable>的情况下才被视为<distributable>
      10. 顶层的<icon>和它的子元素,<display-name><description>元素在一个web片段中被忽略。
      11. jsp-property-group是加法的。当在jar文件的META-INF/resources目录下捆绑静态资源时,建议jsp-config元素使用url-pattern,而不是扩展映射。更多的片段的JSP资源应该在一个与片段名称相同的子目录下,如果存在的话。这有助于防止web-fragment的jsp-property-group影响应用程序主文件根中的JSP,以及jsp-property-group影响fragment的META-INF/resources目录中的JSP。
    9. 对于所有的资源引用元素(env-entryejb-refejblocal-refservice-refresource-refresource-env-refmessage-destination-refpersistence-context-refpersistence-unit-ref)适用以下规则:

      1. 如果任何资源参考元素出现在网络片段中,而在主web.xml中没有,主web.xml继承网络片段的值。如果该元素同时出现在主web.xml和网络片段中,且名称相同,web.xml优先。除了下面指定的injection-target外,片段中的子元素都不会被合并到主web.xml中。例如,如果主web.xml和web片段都声明了一个<resource-ref>,具有相同的<resource-ref-name>web.xml中的<resource-ref>将被使用,除了下面描述的<injection-target>,没有任何子元素被从片段中合并。
      2. 如果在两个片段中指定了一个资源参考元素,而在主web.xml中没有,并且资源参考元素的所有属性和子元素是相同的,资源参考将被合并到主web.xml中。如果一个资源引用元素在两个片段中指定了相同的名称,而不在主web.xml中,并且两个片段中的属性和子元素不相同,这将被视为一个错误。必须报告一个错误,并且应用程序的部署必须失败。例如,如果两个web片段声明一个<resource-ref>,具有相同的<resource-ref-name>元素,但其中一个的类型被指定为javax.sql.DataSource,而另一个的类型是JavaMail资源,这是一个错误,应用程序将无法部署。
      3. 对于具有相同名称的资源参考元素<injection-target>元素将被合并到主web.xml中。
    10. 除了上面定义的web-fragment.xml的合并规则外,在使用资源引用注解(@Resource@Resources@EJB@EJBs@WebServiceRef@WebServiceRefs@PersistenceContext@PersistenceContexts@PersistenceUnit@PersistenceUnits)时适用以下规则

      如果在一个类上应用了资源引用注解,它就相当于定义了一个资源,然而它并不等同于定义了一个 “注射目标”。在这种情况下,上面的规则适用于injection-target元素。

      如果在一个字段上使用了资源引用注解,就相当于在web.xml中定义了注入目标元素。然而,如果描述符中没有injection-target元素,那么片段中的injection-target仍将被合并到web.xml中,如上所述。

      另一方面,如果在主web.xml中有一个injection-target,并且有一个具有相同资源名称的资源引用annotation,那么它被认为是对资源引用注释的覆盖。在这种情况下,由于描述符中指定了injection-target,除了覆盖资源引用注释的值之外,上面定义的规则也将适用。

    11. 如果在两个片段中指定了data-source元素,而在主web.xml中没有,并且data-source元素的所有属性和子元素是相同的,data-source将被合并到主web.xml中。如果一个数据源元素在两个片段中指定了相同的名称,而在主web.xml中没有,并且在两个片段中的属性和子元素不相同,这将被视为一个错误。在这种情况下,必须报告一个错误,并且应用程序必须不能部署。

      下面是一些例子,显示不同情况下的结果。

      CODE EXAMPLE 8-4

      web.xml - no resource-ref definition
      
      
      
      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>
      

      有效的元数据将是

      <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>
      

      CODE EXAMPLE 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>
      

      有效的元数据将是

      <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>
      

      CODE EXAMPLE 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>
      

      有效的元数据将是

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

      以上是关于Servlet规范之注解与可插拔性的主要内容,如果未能解决你的问题,请参考以下文章

      Servlet3.0的可插拔功能

      微服务架构SpringCloud之Feign

      SpringCloud 之Feign服务消费者

      springcloud之服务消费者(feign)

      接口的概述(interface)

      Dubbo源码学习 详解Dubbo里的SPI