servlet3.0无web.xml
大家应该都已经知道spring 3.1对无web.xml式基于代码配置的servlet3.0应用。通过spring的api或是网络上高手们的博文,也一定很快就学会并且加到自己的应用中去了。PS:如果还没,也可以小小参考一下鄙人的上一篇文章<<探 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用>>。
经过一天的深度research, 我了解,理解以及重现了springframework的那一小段代码。
OK,第一步,入手点,WebApplicationInitializer接口。因为我们只需实现这个接口覆写它的一个方法,就可以做到配置web.xml同样的功效。看它的源码,其实看和不看没什么两样:
- package org.springframework.web;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- public interface WebApplicationInitializer {
- void onStartup(ServletContext servletContext) throws ServletException;
- }
就这么点儿,有效代码5行,弄地我一头雾水,就是一个普通接口,声明了一个方法。连注解都没有,server是怎么找到实现了它的类的?如果这样,何不找我定义的其它接口(的实现类完成配置工作)呢。可见现在java的解耦技术,真令人汗颜。
第二步,这个接口旁边(同包)有个SpringServletContainerInitializer, 看下它是何方神圣吧:
- package org.springframework.web;
- import java.lang.reflect.Modifier;
- import java.util.Collections;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.ServiceLoader;
- import java.util.Set;
- import javax.servlet.ServletContainerInitializer;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.HandlesTypes;
- import org.springframework.core.annotation.AnnotationAwareOrderComparator;
- @HandlesTypes(WebApplicationInitializer.class)
- public class SpringServletContainerInitializer implements ServletContainerInitializer {
- public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
- throws ServletException {
- List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
- if (webAppInitializerClasses != null) {
- for (Class<?> waiClass : webAppInitializerClasses) {
- // Be defensive: Some servlet containers provide us with invalid classes,
- // no matter what @HandlesTypes says...
- if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
- try {
- initializers.add((WebApplicationInitializer) waiClass.newInstance());
- }
- catch (Throwable ex) {
- throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
- }
- }
- }
- }
- if (initializers.isEmpty()) {
- servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
- return;
- }
- Collections.sort(initializers, new AnnotationAwareOrderComparator());
- servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
- for (WebApplicationInitializer initializer : initializers) {
- initializer.onStartup(servletContext);
- }
- }
- }
以上的有效代码28行。刚看时也很迷茫,其实慢慢就理解了。拟个伪代码吧,方便大家理解:
1,定义一个类SpringServletContainerInitializer,并标明该类要操作的一个类WebApplicationInitializer
2, 该类会行使ServletContainerInitializer接口的一个行为onStartup,从而将一个集合中的初始化设置 全部配置到ServletContext的实例中。
3,具体的onStartup方法中,建立合格配置列表,
4,如果确定集合中有配置,逐一检查配置是否是合格配置,具体判断依据:这个类不是接口,不是抽象类,而且是所要操作的那个接口的一个实现类。满足此依据,合格。将合格的配置类实例化放入合格配置列表。过程中有错要通知控制台。
5,如若执行完步骤4,发现没有合格配置,在ServletContext记录该结果,并结束onStartup行为。
6,将找到配置按一定排列方式(AnnotationAwareOrder)排序。
7,在ServletContext中记录找到结果。
8,逐一执行配置。 即驱动每一个WebApplicationInitializer的实现类行使其onStartup行为。
第三步很明显了,去research 接口ServletContainerInitializer和注解HandleType。在这里:http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html
该接口允许一个库或运行时,(运行时应该指server)声明为一个web程序的启动状态,并执行任何所需的程序中注册的servlet,filter,listener来响应它......
其它也就不用看了,可以想象得到支持Servlet3机制的服务器,会找到这样接口的实现类,执行onStartup行为。至于如何找,无非也是这样一系列的反射机制的应用。自己做一个试试吧:
自定义的WebApplicationInitializer:
- package com.gxino.imagecapture.cfg;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- public interface WebParameter {
- public void loadInfo(ServletContext servletContext) throws ServletException;
- }
自定义的ServletContainerInitializer,我做得很简单,直接去执行找到配置类中的loadInfo方法
- package com.gxino.imagecapture.cfg;
- import java.lang.reflect.Modifier;
- import java.util.Set;
- import javax.servlet.ServletContainerInitializer;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.HandlesTypes;
- @HandlesTypes(WebParameter.class)
- public class WebConfiguration implements ServletContainerInitializer {
- @Override
- public void onStartup(Set<Class<?>> webParams, ServletContext servletCtx)
- throws ServletException {
- if (webParams != null) {
- for (Class<?> paramClass : webParams) {
- if (!paramClass.isInterface() && !Modifier.isAbstract(paramClass.getModifiers()) &&
- WebParameter.class.isAssignableFrom(paramClass)) {
- try {
- ((WebParameter) paramClass.newInstance()).loadInfo(servletCtx);
- }
- catch (Throwable ex) {
- throw new ServletException("Failed to instantiate WebParam class", ex);
- }
- }
- }//loop
- }//Web Params
- }//onStartup
- }
写个测试Servlet:
- package com.gxino.imagecapture.ctrl;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.gxino.imagecapture.cfg.WebParameter;
- public class TestServlet extends HttpServlet {
- public void doGet(HttpServletRequest req, HttpServletResponse resp){
- System.out.println("Some client access once");
- try {
- req.getRequestDispatcher("/index.jsp").forward(req, resp);
- } catch (ServletException | IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
实现WebParam配置接口来配置刚才的Servlet:
- package com.gxino.imagecapture.cfg;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRegistration;
- public class ServletParameter implements WebParameter {
- @Override
- public void loadInfo(ServletContext servletContext) throws ServletException {
- ServletRegistration.Dynamic testServlet=servletContext.addServlet("test","com.gxino.imagecapture.ctrl.TestServlet");
- testServlet.setLoadOnStartup(1);
- testServlet.addMapping("/index.html");
- }
- }
启动服务器,访问http://localhost:xxxx/xxxxx/index.html
失败。Debug.
发现没有走这些代码。应该还差关键环节。看来还得知道Servlet3中是怎么找ServletContainerInitializer的。再回刚才ServletContainerInitializer的api有这样一句:该接口的实现必须声明一个JAR资源放到程序中的META-INF/services下,并且记有该接口那个实现类的全路径,才会被运行时(server)的查找机制或是其它特定机制找到。那篇api需要仔细阅读啊。
到org.springframework.web-3.0.1.RELEASE.jar中能找到META-INF/services下的javax.servlet.ServletContainerInitializer文件,内容为org.springframework.web.SpringServletContainerInitializer同样,我们专门作这样一个包,在mkdir好的META-INF/services下vi 一个文件命名为javax.servlet.ServletContainerInitializer,内容为自定的那个WebConfiguration的全路径类名。
然后在META-INF的parent路径下运行jar cvf test.jar META-INF。一切完毕,将其放到WEB-INF/lib下。启动。
这回大功告成。
访问http://localhost:xxxx/xxxxx/index.html。页面跳到了index.jsp下。
并且控制台打出: Some client access once
再使个劲,将Servlet和Servlet配置合二为一:
- package com.gxino.imagecapture.ctrl;
- import java.io.IOException;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRegistration;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.gxino.imagecapture.cfg.WebParameter;
- public class TestServlet extends HttpServlet implements WebParameter{
- @Override
- public void loadInfo(ServletContext servletContext) throws ServletException {
- ServletRegistration.Dynamic testServlet=servletContext.addServlet("test", "com.gxino.imagecapture.ctrl.TestServlet");
- testServlet.setLoadOnStartup(1);
- testServlet.addMapping("/index.html");
- }
- public void doGet(HttpServletRequest req, HttpServletResponse resp){
- System.out.println("Some client access once");
- try {
- req.getRequestDispatcher("/index.jsp").forward(req, resp);
- } catch (ServletException | IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
这回我们看到,配置文件与servlet放到了一起。这样将回节省大量时间。
以后直接运用Spring
Framework的WebApplicationInitializer也知道是怎么一回事儿了。而且可以将Spring
的applicationContext.xml与web.xml融合在一个类中。即注解为@Configuration,并实现WebApplicationInitializer.回头试试。
servlet3.0无web.xml的更多相关文章
- DispatcherServlet和ContextLoaderListener,还有spring+servlet3.0 无web.xml启动问题
上篇提到: 关于spring +springmvc中两个spring应用上下文(DispatcherServlet和ContextLoaderListener)的问题,挺让人迷糊的. 他们都是加载Be ...
- springmvc学习指南 之---第27篇 spring如何实现servlet3.0无web.xml 配置servlet对象的
writedby 张艳涛 基于web.xml配置,有人说麻烦,tomcat给按照servlet3.0,实现了基于注解@WebServlet,有人说springmvc的springmvc.xml配置麻烦 ...
- servlet3.0,web.xml的metadata-complete的作用
metadata-complete是servlet3.0规范中的新增的属性,该属性接受两个属性值,true或false.当该属性值为true时,该web应用将不会加载Annotation配置的web组 ...
- WebApplicationInitializer究 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用
本文转自http://hitmit1314.iteye.com/blog/1315816 大家应该都已经知道Spring 3.1对无web.xml式基于代码配置的servlet3.0应用.通过spri ...
- SpringMVC基于代码的配置方式(零配置,无web.xml)直接继承WebMvcConfigurerAdapter
基于配置文件的web项目维护起来可能会更方便,但是有时候我们会有一些特殊的需求,比如防止客户胡乱更改配置,这时候我们需要给配置隐藏到代码中. 1.创建一个动态web项目(无需web.xml) 2.右键 ...
- SpringMVC基于代码的配置方式(零配置,无web.xml)
基于配置文件的web项目维护起来可能会更方便,可是有时候我们会有一些特殊的需求,比方防止客户胡乱更改配置,这时候我们须要给配置隐藏到代码中. 1.创建一个动态web项目(无需web.xml) 2.右键 ...
- SpringMVC 零配置 无web.xml
对SpringMVC启动流程的讲解 https://www.cnblogs.com/beiyan/p/5942741.html 与SpringMVC的整合 https://hanqunfeng.ite ...
- web.xml 中以编码方式添加filter并设置初始化参数AbstractAnnotationConfigDispatchServletInitializer
web.xml中配置filter <?xml version="1.0" encoding="UTF-8"?> <web-app versio ...
- servlet3.0 JQuary Ajax基本使用
servlet3.0 没有web.xml文件,需要使用注解进行配置. js: $(document).ready(function(){ $("#btn").click(funct ...
随机推荐
- C# 连接 Oracle数据库增删改查,事务
一. 前情提要 一般.NET环境连接Oracle数据库,是通过 TNS/SQL.NET 配置文件,而 TNS 必须要 Oracle 客户端(如果连接的是服务器的数据库,本地还要装一个 client , ...
- springboot(十八)-session共享
前言 在传统的单服务架构中,一般来说,只有一个服务器,那么不存在 Session 共享问题,但是在分布式/集群项目中,Session 共享则是一个必须面对的问题,先看一个简单的架构图: 在这样的架构中 ...
- Android官方网站!
Android官方网站,所有Android相关文档.官方工具.示例,全部都在上面!! http://www.android.com/
- dedecms 列表 用分页标签 判断 当第一页则显示,第二页以上不显示 土办法!
arc.listview.class.php function GetPageListST($list_len,$listitem="index,end,pre,next,pageno,sp ...
- symfony3 yml配置文件详解
AppBundle\Entity\BlogComment: //映射实体 type: entity //类型 repositoryClass: AppBundle\Repository ...
- nginx服务学习第一章
一.ubuntu系统安装nginx服务 # apt-get install nginx 二.nginx.config配置文件详解 配置文件结构: 全局块(全局变量) events{ } http{ h ...
- centos7搭建ntp时间同步服务器chrony服务
centos7搭建ntp时间同步服务器chrony服务 前言: 在centos6的时候我们基本使用的是ntp服务用来做时间同步,但是在centos7后推荐是chrony作为时间同步器的服务端使用, ...
- 15 Zabbix4.4.1系统告警“sda: Disk read/write request response are too high”
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 Zabbix4.4.1系统告警“sda: Disk read/write request resp ...
- zk和eureka的区别(CAP原则)
作为服务注册中心,Eureka比Zookeeper好在哪里 著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性).A(可用性)和P(分区容错性).由于分区容错性在是分布式系统中必须要保证的, ...
- PAT Basic 1019 数字黑洞 (20 分)
给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字.一直重复这样做,我们很快会停在有“数字黑洞 ...