• Spring中WebApplicationInitializer的理解


        现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代,它是一个接口。通过实现WebApplicationInitializer,在其中可以添加servlet,listener等,在加载Web项目的时候会加载这个接口实现类,从而起到web.xml相同的作用。下面就看一下这个接口的详细内容。

         首先打开这个接口,如下:

    1. public interface WebApplicationInitializer {
    2. void onStartup(ServletContext var1) throws ServletException;
    3. }

         只有一个方法,看不出什么头绪。但是,在这个包下有另外一个类,SpringServletContainerInitializer。它的实现如下:

    1. package org.springframework.web;
    2. import java.lang.reflect.Modifier;
    3. import java.util.Iterator;
    4. import java.util.LinkedList;
    5. import java.util.List;
    6. import java.util.Set;
    7. import javax.servlet.ServletContainerInitializer;
    8. import javax.servlet.ServletContext;
    9. import javax.servlet.ServletException;
    10. import javax.servlet.annotation.HandlesTypes;
    11. import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    12. @HandlesTypes({WebApplicationInitializer.class})
    13. public class SpringServletContainerInitializer implements ServletContainerInitializer {
    14. public SpringServletContainerInitializer() {
    15. }
    16. public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
    17. List<WebApplicationInitializer> initializers = new LinkedList();
    18. Iterator var4;
    19. if(webAppInitializerClasses != null) {
    20. var4 = webAppInitializerClasses.iterator();
    21. while(var4.hasNext()) {
    22. Class<?> waiClass = (Class)var4.next();
    23. if(!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
    24. try {
    25. initializers.add((WebApplicationInitializer)waiClass.newInstance());
    26. } catch (Throwable var7) {
    27. throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
    28. }
    29. }
    30. }
    31. }
    32. if(initializers.isEmpty()) {
    33. servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
    34. } else {
    35. servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
    36. AnnotationAwareOrderComparator.sort(initializers);
    37. var4 = initializers.iterator();
    38. while(var4.hasNext()) {
    39. WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
    40. initializer.onStartup(servletContext);
    41. }
    42. }
    43. }
    44. }

        这个类就比较有意思了,先不管其他的,读一下这段代码,可以得到这样的意思。

                 先判断webAppInitializerClasses这个Set是否为空。如果不为空的话,找到这个set中不是接口,不是抽象类,并且是

    WebApplicationInitializer接口实现类的类,将它们保存到list中。当这个list为空的时候,抛出异常。不为空的话就按照一定的顺序排序,并将它们按照一定的顺序实例化。调用其onStartup方法执行。到这里,就可以解释WebApplicationInitializer实现类的工作过程了。但是,在web项目运行的时候,SpringServletContainerInitializer这个类又是怎样被调用的呢。

               它只有一个接口,ServletContainerInitializer,通过它就可以解释SpringServletContainerInitializer是如何被调用的。它的内容如下,

    1. package javax.servlet;
    2. import java.util.Set;
    3. public interface ServletContainerInitializer {
    4. void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException;
    5. }

               首先,这个接口是javax.servlet下的。官方的解释是这样的:为了支持可以不使用web.xml。提供了ServletContainerInitializer,它可以通过SPI机制,当启动web容器的时候,会自动到添加的相应jar包下找到META-INF/services下以ServletContainerInitializer的全路径名称命名的文件,它的内容为ServletContainerInitializer实现类的全路径,将它们实例化。既然这样的话,那么SpringServletContainerInitializer作为ServletContainerInitializer的实现类,它的jar包下也应该有相应的文件。打开查看如下:

                                

             哈,现在就可以解释清楚了。首先,SpringServletContainerInitializer作为ServletContainerInitializer的实现类,通过SPI机制,在web容器加载的时候会自动的被调用。(这个类上还有一个注解@HandlesTypes,它的作用是将感兴趣的一些类注入到ServletContainerInitializerde), 而这个类的方法又会扫描找到WebApplicationInitializer的实现类,调用它的onStartup方法,从而起到启动web.xml相同的作用。

             然后,我们自己通过一个实例来实现相同的功能,通过一样的方式来访问一个servlet。

            

             1、定义接口WebParameter,它就相当于WebApplicationInitializer。内容如下:

    1. public interface WebParameter {
    2. void loadOnstarp(ServletContext servletContext);
    3. }

              可以在这里面添加servlet,listener等。

           2、定义Servlet。

    1. public class MyServlet extends HttpServlet {
    2. @Override
    3. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    4. resp.getWriter().write("TestSetvlet");
    5. }
    6. }

           3、定义MyWebParameter作为WebParameter的实现类,将Servlet添加到上下文,并设置好映射。

    1. public class MyWebParameter implements WebParameter {
    2. public void loadOnstarp(ServletContext servletContext) {
    3. ServletRegistration.Dynamic testSetvelt=servletContext.addServlet("test","com.test.servlet.MyServlet");
    4. testSetvelt.setLoadOnStartup(1);
    5. testSetvelt.addMapping("/test");
    6. }
    7. }

           4、定义好WebConfig作为ServletContainerInitializer的实现类,它的作用是扫描找到WebParameter的实现类,并调用其方法。 

    1. @HandlesTypes({WebParameter.class})
    2. public class WebConfig implements ServletContainerInitializer {
    3. public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
    4. Iterator var4;
    5. if (set!=null){
    6. var4=set.iterator();
    7. while(var4.hasNext()){
    8. Class<?> clazz= (Class<?>) var4.next();
    9. if (!clazz.isInterface()&& !Modifier.isAbstract(clazz.getModifiers())&&WebParameter.class.isAssignableFrom(clazz)){
    10. try {
    11. ((WebParameter) clazz.newInstance()).loadOnstarp(servletContext);
    12. }catch (Exception e){
    13. e.printStackTrace();
    14. }
    15. }
    16. }
    17. }
    18. }
    19. }

             5、根据SPI机制,定义一个META-INF/services文件夹,并在其下定义相关文件名称,并将WebConfig的类全名称填入其中。

                  

                  至此,相关内容就完成了,因为我用的maven,通过install将其作为jar包上传到本地仓库。从另外一个web项目调用这个包进行访问。

             6、最终结果:

                         


                相关代码请转至我的github点击打开链接

    ps:其中涉及到了SPI相关的内容,如果不懂请自行百度。如果认识有误,请大佬指出,谢谢。






           

  • 相关阅读:
    用户界面线程(含有消息泵的线程)主线程与用户界面线程的通信
    poj 2151 Check the difficulty of problems 概率dp
    Codeforces 148D Bag of mice 概率dp
    [置顶] UVa在线比赛单题汇总DP专题
    UVa 10405 Longest Common Subsequence 最长公共子序列模板
    UVa 12018 Juice Extractor 切水果dp暂时存疑
    UVa 674 Coin Change 背包dp
    hdu 3853 LOOPS 圆环之理 概率dp
    UVa 111 History Grading 最长递增子序列 LIS
    UVa在线比赛单题汇总DP专题
  • 原文地址:https://www.cnblogs.com/jpfss/p/9719676.html
Copyright © 2020-2023  润新知