读书人

究 Spring 3.1之无web.xml式 基于代码

发布时间: 2012-07-01 13:15:00 作者: rapoo

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

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

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

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

Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)

  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, 看下它是何方神圣吧:?
Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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:?

Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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方法?

Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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:?

Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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:?

Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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配置合二为一:?
Java代码??究 Spring 3.1之无web.xml式 基于代码配备的servlet3.0应用(转)
  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.回头试试。

读书人网 >Web前端

热点推荐