首页 > 其他分享 >WebApplicationInitializer究 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用

WebApplicationInitializer究 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用

时间:2023-05-15 09:01:29浏览次数:56  
标签:xml web ServletException Spring ServletContext WebApplicationInitializer import 

大家应该都已经知道Spring 3.1对无web.xml式基于代码配置的servlet3.0应用。通过spring的api或是网络上高手们的博文,也一定很快就学会并且加到自己的应用中去了。PS:如果还没,也可以小小参考一下鄙人的上一篇文章<<探 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用>>。 

        经过一天的深度research, 我了解,理解以及重现了springframework的那一小段代码。 

        OK,第一步,入手点,WebApplicationInitializer接口。因为我们只需实现这个接口覆写它的一个方法,就可以做到配置web.xml同样的功效。看它的源码,其实看和不看没什么两样: 

  1. package org.springframework.web;  
  2.   
  3. import javax.servlet.ServletContext;  
  4. import javax.servlet.ServletException;  
  5. public interface WebApplicationInitializer {  
  6.     void onStartup(ServletContext servletContext) throws ServletException;  
  7. }  


   就这么点儿,有效代码5行,弄地我一头雾水,就是一个普通接口,声明了一个方法。连注解都没有,server是怎么找到实现了它的类的?如果这样,何不找我定义的其它接口(的实现类完成配置工作)呢。可见现在java的解耦技术,真令人汗颜。

 

 第二步,这个接口旁边(同包)有个SpringServletContainerInitializer, 看下它是何方神圣吧: 

  1. package org.springframework.web;  
  2.   
  3. import java.lang.reflect.Modifier;  
  4. import java.util.Collections;  
  5. import java.util.LinkedList;  
  6. import java.util.List;  
  7. import java.util.ServiceLoader;  
  8. import java.util.Set;  
  9. import javax.servlet.ServletContainerInitializer;  
  10. import javax.servlet.ServletContext;  
  11. import javax.servlet.ServletException;  
  12. import javax.servlet.annotation.HandlesTypes;  
  13.   
  14. import org.springframework.core.annotation.AnnotationAwareOrderComparator;  
  15.   
  16. @HandlesTypes(WebApplicationInitializer.class)  
  17. public class SpringServletContainerInitializer implements ServletContainerInitializer {  
  18. public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)  
  19.             throws ServletException {  
  20.   
  21.         List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();  
  22.         if (webAppInitializerClasses != null) {  
  23.             for (Class<?> waiClass : webAppInitializerClasses) {  
  24.                 // Be defensive: Some servlet containers provide us with invalid classes,  
  25.                 // no matter what @HandlesTypes says...  
  26.                 if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&             WebApplicationInitializer.class.isAssignableFrom(waiClass)) {  
  27.                     try {  
  28.                         initializers.add((WebApplicationInitializer) waiClass.newInstance());  
  29.                     }  
  30.                     catch (Throwable ex) {  
  31.                         throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);  
  32.                     }  
  33.                 }  
  34.             }  
  35.         }  
  36.   
  37.         if (initializers.isEmpty()) {  
  38.             servletContext.log("No Spring WebApplicationInitializer types detected on classpath");  
  39.             return;  
  40.         }  
  41.   
  42.         Collections.sort(initializers, new AnnotationAwareOrderComparator());  
  43.         servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);  
  44.   
  45.         for (WebApplicationInitializer initializer : initializers) {  
  46.             initializer.onStartup(servletContext);  
  47.         }  
  48.     }  
  49.   
  50. }  



     以上的有效代码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: 

  1. package com.gxino.imagecapture.cfg;  
  2.   
  3. import javax.servlet.ServletContext;  
  4. import javax.servlet.ServletException;  
  5.   
  6. public interface WebParameter {  
  7.     public void loadInfo(ServletContext servletContext) throws ServletException;  
  8. }  



     自定义的ServletContainerInitializer,我做得很简单,直接去执行找到配置类中的loadInfo方法 

  1. package com.gxino.imagecapture.cfg;  
  2.   
  3. import java.lang.reflect.Modifier;  
  4. import java.util.Set;  
  5.   
  6. import javax.servlet.ServletContainerInitializer;  
  7. import javax.servlet.ServletContext;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.annotation.HandlesTypes;  
  10.   
  11. @HandlesTypes(WebParameter.class)  
  12. public class WebConfiguration implements ServletContainerInitializer {  
  13.   
  14.     @Override  
  15.     public void onStartup(Set<Class<?>> webParams, ServletContext servletCtx)  
  16.             throws ServletException {  
  17.         if (webParams != null) {  
  18.             for (Class<?> paramClass : webParams) {  
  19.                 if (!paramClass.isInterface() && !Modifier.isAbstract(paramClass.getModifiers()) &&  
  20.                         WebParameter.class.isAssignableFrom(paramClass)) {  
  21.                     try {  
  22.                         ((WebParameter) paramClass.newInstance()).loadInfo(servletCtx);  
  23.                     }  
  24.                     catch (Throwable ex) {  
  25.                         throw new ServletException("Failed to instantiate WebParam class", ex);  
  26.                     }  
  27.                 }  
  28.             }//loop  
  29.         }//Web Params  
  30.     }//onStartup  
  31.   
  32. }  


      写个测试Servlet: 

  1. package com.gxino.imagecapture.ctrl;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import com.gxino.imagecapture.cfg.WebParameter;  
  11.   
  12. public class TestServlet extends HttpServlet {  
  13.       
  14.     public void doGet(HttpServletRequest req, HttpServletResponse resp){  
  15.         System.out.println("Some client access once");  
  16.         try {  
  17.             req.getRequestDispatcher("/index.jsp").forward(req, resp);  
  18.         } catch (ServletException | IOException e) {  
  19.             // TODO Auto-generated catch block  
  20.             e.printStackTrace();  
  21.         }  
  22.     }  
  23.       
  24. }  



       实现WebParam配置接口来配置刚才的Servlet: 

  1. package com.gxino.imagecapture.cfg;  
  2.   
  3. import javax.servlet.ServletContext;  
  4. import javax.servlet.ServletException;  
  5. import javax.servlet.ServletRegistration;  
  6.   
  7.   
  8. public class ServletParameter implements WebParameter {  
  9.   
  10.     @Override  
  11.     public void loadInfo(ServletContext servletContext) throws ServletException {  
  12.         ServletRegistration.Dynamic testServlet=servletContext.addServlet("test","com.gxino.imagecapture.ctrl.TestServlet");  
  13.         testServlet.setLoadOnStartup(1);  
  14.         testServlet.addMapping("/index.html");  
  15.     }  
  16.   
  17. }  


     启动服务器,访问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配置合二为一: 

  1. package com.gxino.imagecapture.ctrl;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.ServletContext;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.ServletRegistration;  
  8. import javax.servlet.http.HttpServlet;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletResponse;  
  11.   
  12. import com.gxino.imagecapture.cfg.WebParameter;  
  13.   
  14. public class TestServlet extends HttpServlet implements WebParameter{  
  15.   
  16.     @Override  
  17.     public void loadInfo(ServletContext servletContext) throws ServletException {  
  18.         ServletRegistration.Dynamic testServlet=servletContext.addServlet("test", "com.gxino.imagecapture.ctrl.TestServlet");  
  19.         testServlet.setLoadOnStartup(1);  
  20.         testServlet.addMapping("/index.html");  
  21.     }  
  22.     public void doGet(HttpServletRequest req, HttpServletResponse resp){  
  23.         System.out.println("Some client access once");  
  24.         try {  
  25.             req.getRequestDispatcher("/index.jsp").forward(req, resp);  
  26.         } catch (ServletException | IOException e) {  
  27.             // TODO Auto-generated catch block  
  28.             e.printStackTrace();  
  29.         }  
  30.     }  
  31.       
  32. }  



这回我们看到,配置文件与servlet放到了一起。这样将回节省大量时间。 

    以后直接运用Spring Framework的WebApplicationInitializer也知道是怎么一回事儿了。而且可以将Spring 的applicationContext.xml与web.xml融合在一个类中。即注解为@Configuration,并实现WebApplicationInitializer.回头试试。

 

转https://blog.csdn.net/xiao__gui/article/details/46803193

https://www.cnblogs.com/zytcomeon/p/15091369.html

https://www.cnblogs.com/aji2014/p/6694361.html

标签:xml,web,ServletException,Spring,ServletContext,WebApplicationInitializer,import,
From: https://www.cnblogs.com/smallfa/p/17400788.html

相关文章

  • Table被web编程弃用的原因
    Table要比其它html标记占更多的字节。(延迟下载时间,占用服务器更多的流量资源。)Tablle会阻挡浏览器渲染引擎的渲染顺序。(会延迟页面的生成速度,让用户等待更久的时间。)Table里显示图片时需要你把单个、有逻辑性的图片切成多个图。(增加设计的复杂度,增加页面加载时间,增加HTTP会话......
  • 关于 Web 可访问性的神话
    网络可访问性是每个Web开发项目中的必去之处,但对于许多Web开发人员来说,它似乎仍是个谜。就像这是传奇的东西,而不是工作所需的基本技能。围绕Web可访问性存在许多误解,大多数时候,由于对此事缺乏了解(或兴趣),这些误解都助长了这种误解。本文收集了其中一些无障碍误解或神话。无......
  • pom.xml详解
    <projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd">&......
  • 一天吃透SpringCloud面试八股文
    1、什么是SpringCloud?Springcloud流应用程序启动器是基于SpringBoot的Spring集成应用程序,提供与外部系统的集成。SpringcloudTask,一个生命周期短暂的微服务框架,用于快速构建执行有限数据处理的应用程序。SpringCloud各个微服务之间为什么要用http交互?难道不慢吗?Spr......
  • docker compose fullstack example -- keycloak web grant-type: password
    fastapi-react-postgres-keycloak-ssohttps://github.com/fanqingsong/fastapi-react-postgres-keycloak-sso version:"3"services:nginx:image:nginx:1.17volumes:-./nginx/nginx.conf:/etc/nginx/conf.d/default.conf-./log......
  • WEB—加密算法
    前言:在渗透测试中,常见的密码等敏感信息会采用加密处理,其中作为安全测试人员必须要了解常见的加密方式,才能为后续的安全测试做好准备————————————————————————————————————————————常见加密编码等算法解析MD5,SHA,ASC,进制,时间戳,U......
  • 【转载】SpringBoot自带的工具类
    断言对象、数组、集合ObjectUtilsStringUtilsCollectionUtils文件、资源、IO流FileCopyUtilsResourceUtilsStreamUtils反射、AOPReflectionUtils[AopUtils][AopContext]最近发现同事写了不少重复的工具类,发现其中很多功能,Spring自带的都有。于是整......
  • 老杜 JavaWeb 讲解(六) ——Servlet对象的生命周期
    (八)Servlet对象的生命周期对应视频:10-Servlet对象的生命周期8.1什么是Servlet对象生命周期?Servlet对象什么时候被创建。Servlet对象什么时候被销毁。Servlet对象创建了几个?Servlet对象的生命周期表示:一个Servlet对象从出生在最后的死亡,整个过程是怎样的。8.2Servle......
  • 利用SpringBoot实现增删改查
    启动类//@MapperScan("")//@SpringApplicationpackagecom.example.demo;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@Mapp......
  • 【从0开始编写webserver·基础篇#01】为什么需要线程池?写一个线程池吧
    线程池参考:1、游双Linux高性能服务器编程2、TinyWebServer注:虽然是"从0开始",但最好对(多)线程、线程同步等知识点有所了解再看,不然可能有些地方会理解不到位(但也有可能是我没说明到位,水平有限,见谅)Web服务器与线程池的关系Web服务器需要同时处理多个客户端请求,并且每个请求可......