起源之路——Servlet(七)

注解和可插拔性

注解的使用

在web应用中,使用注解的类只有在位于WEB-INF/classes目录或被打包到应用的WEB-INF/lib中的jar文件时,才能生效。在Web应用部署描述符的web-app元素中包含一个新的“metadata-complate”属性。该属性定义了web描述符是否是完整的,或者是否应该在部署时检查jar包中的类文件和web fragments。当该属性为“true”时,部署工具必须忽略存在于应用的类文件中的所有指定部署信息的servlet注解和web fragments。若为“false”或无值,部署工具必须检查应用的类文件的注解,并扫描web fragments。

@WebServlet

该注解用于在web应用中定义servlet组件。它在一个类上使用并指定包含生命servlet的元数据。必须指定UrlPattern或value属性。同一注解上同时使用value和urlPattern是非法的。如果没有指定servlet名字则默认为全限定类名。被注解的servlet必须指定至少一个url模式进行部署。如果该servlet以不同名字声明在部署描述符中,必须实例化一个新的servlet实例。如果使用不同名字添加的同一个servlet类,需要使用编程式API添加到servletContext。此时@WebServlet注解的声明属性必须忽略。必须重新创建一个指定名字的Servlet新实例。注意:@WebServlet注解的类必须继承javax.servlet.http.HttpServlet类。

@WebFilter

该注解用于在Web应用中定义Filter。它在一个类上使用并指定包含声明过滤器的元数据。大部分特性与WebServlet注解基本一致。

WebInitParam

该注解指定必须要传递给Servlet或Filter的初始化参数。是WebServlet和WebFilter注解的属性之一。

WebListener

用于获取特定web应用上下文中的各种操作时间的监听器。被该注解注释的类,必须实现以下接口:

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

@MultipartConfig

当该注解指定在Servlet上时,表示请求期望是mime/multipart类型。想应servlet的HttpServletRequest对象必须使用getParts和getPart方法遍历各个mime附件,获取数据。
javax.servlet.annotation.MultipartConfig的location属性和<multipart-config>标签的<location>元素被解析为默认javax.servlet.context.tempdir。如果指定了相对路径,他将是相对tempdir位置。绝对路径和相对路径的测试必须使用java.io.File.isAbsolute。

可插拔性

使用上述注解使web.xml的使用变为可选。 对于覆盖默认值,或使用注解设置的值,仍然需要使用部署描述符。

web fragment的概念(web模块部署描述符片段)

它是web.xml的部分或全部,可以在一个类库或框架jar包的META-INF目录制定和包括。在该目录中的普通的老jar文件即使没有web-fragment.xml也可能被认为是一个fragment,任何在它中制定的注解都将按照一组已定义的装配规则处理。容器会取出他们并按照定义的规则进行配置。
它就是Web应用的一个逻辑分区,以这种方式在应用中使用框架可以定义所有artifact(我理解为组件),无需开发人员在web.xml中编辑或添加信息。它几乎包含web.xml中使用的所有相同元素,但是他的描述符顶级元素必须是web-fragment且对应的描述文件必须被称为web-fragment.xml。
如果框架打包成jar文件,且有部署描述符形式的元数据信息,那么web-fragment.xml描述符必须在该jar包的META-INF/目录中。如果框架想要使用META-INF/web-fragment.xml,以这种方式扩充web.xml,框架必须被绑定到Web应用的WEB-INF/lib目录中。为了使框架中的任何其他类型的资源对web应用可用。把框架防止在web应用的classloader委托链的任意位置即可。
在部署期间,容器负责扫描上面指定的位置和发现web-fragment.xml并处理他们。

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

web-fragment.xml中有且仅有一个javaee:java-identifierType类型的顶级元素,它被用于考虑artifact顺序,绝对顺序和相对顺序两种情况必须被考虑。

绝对顺序

在web.xml中的<absolute-ordering>元素。在一个web.xml中仅有一个<absolute-ordering>

  • 这种情况下,第二种情况处理的顺序配置必须被忽略
  • web.xml和WEB-INF/classses必须列在absolute-ordering元素中的所有web-fragment之前处理。
  • <absolute-ordering>的任何直接子name元素必须被解释为在这些被指定的web-fragment中表示绝对顺序,无论它是否存在,都要被处理。
  • <absolute-ordering>可以包含0或1个others元素;如通过<absolute-ordering>元素没有包含others元素,则没有在name元素中明确提到的web-fragment必须被忽略,不会扫描被排除的jar包中的上述注解。如果是被排除jar包中的上述注解,其列在web.xml或非排除的web-fragment.xml中那么他的注解讲使用除非另外使用的metadata-complate排除。在排除的jar包的TLD文件中发现的ServletContextListener不能使用编程式API配置FIlter和Servlet,该操作会抛出IllegalStateException。如果发现ServletContainerInitializer是从一个被排除的jar包中装载的,他将被忽略。无论是否设置了metadata-complate,通过<absolute-ordering>排除的jar包不扫描被任何ServletContainerInitializer处理的类。
  • 重名异常,当遍历<absolute-ordering>子元素遇到多个子元素具有相同name,只考虑首次出现的。
相对顺序

在web-fragment.xml中的ordering元素,一个web-fragment.xml中只能有一个ordering元素。

  • web-fragment可以有一个ordering元素。如果是这样,该元素必须包含零个或一个before元素和after元素。
  • web.xml和WEB-INF/classes必须在列在ordering元素中的所有web-fragment之前处理。
  • 重名异常;当遍历web-fragments,遇到多个成员具有相同的name元素,应用必须记录包含帮助解决这个问题的错误信息,且部署失败。

装配web.xml、web-fragment.xml描述符和注解的规则

  1. 如果有关的Listener、Servlet和Filter的顺序必须指定,那么必须在web-fragment.xml或web.xml中指定。
  2. 顺序依据他们定义在描述符中的顺序和依赖于web.xml中存在的absolute-ordering元素或web-fragment.xml中存在的ordering元素。
    • 匹配请求的过滤器链的顺序是他们在web.xml中声明的顺序。
    • Servlet在请求处理时实例化或在部署时立即实例化。在后一种情况,以他们的load-on-startup元素指定的顺序实例化。
    • 在Servlet3.0中,Listener以他们在web.xml中生命的顺序调用,如下:
      • javax.servlet.ServletContextListener实现的contextInitialized方法以声明时顺序调用,contextDestroyed以相反的顺序调用。
      • javax.servlet.ServletRequestListener实现的requestInitialized以声明时顺序调用,对应destroyed方法以相反顺序调用。
      • javax.servlet.http.HttpSessionListener实现的sessionCreated以声明时顺序调用,对应destroyed方法以相反顺序调用。
      • 当相应事件触发时,javax.servlet.ServletContextAttributeListener、javax.servlet.ServletRequestAttributeListener和javax.servlet.HTTPSessionAttributeListener的方法按照它们声明的顺序调用
  3. 如果在web.xml使用enabled元素禁用引入的servlet那么该servlet对指定的url-pattern不可用
  4. 当在web.xml、web-fragment.xml和注解之间解析发生冲突时web应用的web.xml具有最高优先级
  5. 如果没有在描述符中指定metadata-complate或在部署描述符中设置为false,通过组合出现在注解和描述符中的metadata导出有效的metadata

共享库/运行时可插拔性

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

除此之外,还有一个HandlesTypes注解。用于表示感兴趣的一些类,他们可能指定可handlesTypes的value中的注解(类型、方法或自动级别的注解),或者是其类型的超类继承/实现了这些类之一,无论是否设置metadata-complate,HandlesTypes注解都被应用。

当检测一个应用的类是否匹配ServletContainerInitializer的HandlesTypes指定的条件时,若应用的一个或多个可选的JAR包确实,容器可能遇到类装载问题。由于容器不能决定这些类型的类装载失败讲阻止应用正常工作,容器必须忽略它们,同时也提供一个将记录它们的配置选项。

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

在任何Servlet Listener的事件被触发之前,当应用正在启动时,ServletContainerInitializer的onStartup方法将被调用。 ServletContainerInitializer的onStartup得到一个类的Set,其或者继承/实现initializer表示感兴趣的类,或者它是使用指定在@HandlesTypes注解中的任意类注解的。


参考链接: 来自waylau翻译的《Java Servlet 3.1 规范》
自己使用整理收集,如有侵权 请联系删除!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值