zoukankan      html  css  js  c++  java
  • Spring之WebContext不使用web.xml启动 初始化重要的类源码分析(Servlet3.0以上的)

    入口:

    org.springframework.web.SpringServletContainerInitializer implements ServletContainerInitializer
    org.springframework.web.WebApplicationInitializer

    ServletContainerInitializer这个类是Servlet3.0新增的接口,源码定义如下:

    package javax.servlet;
    
    import java.util.Set;
    
    /**
     * ServletContainerInitializers (SCIs) are registered via an entry in the
     * file META-INF/services/javax.servlet.ServletContainerInitializer that must be
     * included in the JAR file that contains the SCI implementation.
     * <p>
     * SCI processing is performed regardless of the setting of metadata-complete.
     * SCI processing can be controlled per JAR file via fragment ordering. If an
     * absolute ordering is defined, the only those JARs included in the ordering
     * will be processed for SCIs. To disable SCI processing completely, an empty
     * absolute ordering may be defined.
     * <p>
     * SCIs register an interest in annotations (class, method or field) and/or
     * types via the {@link javax.servlet.annotation.HandlesTypes} annotation which
     * is added to the class.
     *
     * @since Servlet 3.0
     */
    public interface ServletContainerInitializer {
    
        /**
         * Receives notification during startup of a web application of the classes
         * within the web application that matched the criteria defined via the
         * {@link javax.servlet.annotation.HandlesTypes} annotation.
         *
         * @param c     The (possibly null) set of classes that met the specified
         *              criteria
         * @param ctx   The ServletContext of the web application in which the
         *              classes were discovered
         *
         * @throws ServletException If an error occurs
         */
        void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
    }

    而SpringServletContainerInitializer实现了这个接口,源码也很简单的只有几行,这里原封不动的将注释也拷过来,便于读懂注释分析:

    /**
     * Servlet 3.0 {@link ServletContainerInitializer} designed to support code-based
     * configuration of the servlet container using Spring's {@link WebApplicationInitializer}
     * SPI as opposed to (or possibly in combination with) the traditional
     * {@code web.xml}-based approach.
     *
     * <h2>Mechanism of Operation</h2>
     * This class will be loaded and instantiated and have its {@link #onStartup}
     * method invoked by any Servlet 3.0-compliant container during container startup assuming
     * that the {@code spring-web} module JAR is present on the classpath. This occurs through
     * the JAR Services API {@link ServiceLoader#load(Class)} method detecting the
     * {@code spring-web} module's {@code META-INF/services/javax.servlet.ServletContainerInitializer}
     * service provider configuration file. See the
     * <a href="http://download.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider">
     * JAR Services API documentation</a> as well as section <em>8.2.4</em> of the Servlet 3.0
     * Final Draft specification for complete details.
     *
     * <h3>In combination with {@code web.xml}</h3>
     * A web application can choose to limit the amount of classpath scanning the Servlet
     * container does at startup either through the {@code metadata-complete} attribute in
     * {@code web.xml}, which controls scanning for Servlet annotations or through an
     * {@code <absolute-ordering>} element also in {@code web.xml}, which controls which
     * web fragments (i.e. jars) are allowed to perform a {@code ServletContainerInitializer}
     * scan. When using this feature, the {@link SpringServletContainerInitializer}
     * can be enabled by adding "spring_web" to the list of named web fragments in
     * {@code web.xml} as follows:
     *
     * <pre class="code">
     * {@code
     * <absolute-ordering>
     *   <name>some_web_fragment</name>
     *   <name>spring_web</name>
     * </absolute-ordering>
     * }</pre>
     *
     * <h2>Relationship to Spring's {@code WebApplicationInitializer}</h2>
     * Spring's {@code WebApplicationInitializer} SPI consists of just one method:
     * {@link WebApplicationInitializer#onStartup(ServletContext)}. The signature is intentionally
     * quite similar to {@link ServletContainerInitializer#onStartup(Set, ServletContext)}:
     * simply put, {@code SpringServletContainerInitializer} is responsible for instantiating
     * and delegating the {@code ServletContext} to any user-defined
     * {@code WebApplicationInitializer} implementations. It is then the responsibility of
     * each {@code WebApplicationInitializer} to do the actual work of initializing the
     * {@code ServletContext}. The exact process of delegation is described in detail in the
     * {@link #onStartup onStartup} documentation below.
     *
     * <h2>General Notes</h2>
     * In general, this class should be viewed as <em>supporting infrastructure</em> for
     * the more important and user-facing {@code WebApplicationInitializer} SPI. Taking
     * advantage of this container initializer is also completely <em>optional</em>: while
     * it is true that this initializer will be loaded and invoked under all Servlet 3.0+
     * runtimes, it remains the user's choice whether to make any
     * {@code WebApplicationInitializer} implementations available on the classpath. If no
     * {@code WebApplicationInitializer} types are detected, this container initializer will
     * have no effect.
     *
     * <p>Note that use of this container initializer and of {@code WebApplicationInitializer}
     * is not in any way "tied" to Spring MVC other than the fact that the types are shipped
     * in the {@code spring-web} module JAR. Rather, they can be considered general-purpose
     * in their ability to facilitate convenient code-based configuration of the
     * {@code ServletContext}. In other words, any servlet, listener, or filter may be
     * registered within a {@code WebApplicationInitializer}, not just Spring MVC-specific
     * components.
     *
     * <p>This class is neither designed for extension nor intended to be extended.
     * It should be considered an internal type, with {@code WebApplicationInitializer}
     * being the public-facing SPI.
     *
     * <h2>See Also</h2>
     * See {@link WebApplicationInitializer} Javadoc for examples and detailed usage
     * recommendations.<p>
     *
     * @author Chris Beams
     * @author Juergen Hoeller
     * @author Rossen Stoyanchev
     * @since 3.1
     * @see #onStartup(Set, ServletContext)
     * @see WebApplicationInitializer
     */
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
    
        /**
         * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
         * implementations present on the application classpath.
         * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
         * Servlet 3.0+ containers will automatically scan the classpath for implementations
         * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
         * such types to the {@code webAppInitializerClasses} parameter of this method.
         * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
         * this method is effectively a no-op. An INFO-level log message will be issued notifying
         * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
         * no {@code WebApplicationInitializer} implementations were found.
         * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
         * they will be instantiated (and <em>sorted</em> if the @{@link
         * org.springframework.core.annotation.Order @Order} annotation is present or
         * the {@link org.springframework.core.Ordered Ordered} interface has been
         * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
         * method will be invoked on each instance, delegating the {@code ServletContext} such
         * that each instance may register and configure servlets such as Spring's
         * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
         * or any other Servlet API componentry such as filters.
         * @param webAppInitializerClasses all implementations of
         * {@link WebApplicationInitializer} found on the application classpath
         * @param servletContext the servlet context to be initialized
         * @see WebApplicationInitializer#onStartup(ServletContext)
         * @see AnnotationAwareOrderComparator
         */
        @Override
        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;
            }
    
            servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
            AnnotationAwareOrderComparator.sort(initializers);
            for (WebApplicationInitializer initializer : initializers) {
                initializer.onStartup(servletContext);
            }
        }
    
    }

    TODO:

    另外, 这个ServletContainerInitializer的执行是在 ServletContextListener之前,可以做个试验看看,这里我写一个简单的TestListener,代码如下

    @WebListener
    public class TestListener implements ServletContextListener{
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.err.println("执行listener ......................");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
    
        }
    }

    同时在上面的ServletApplicationInitializer 的onStartup方法第一行也加一个打印语句:

    public class ServletApplicationInitializer implements WebApplicationInitializer {
    
        @Override
        public void onStartup(ServletContext container) {
            System.err.println("执行3.0 的ServletApplicationInitializer.................");
            //now add the annotations
            AnnotationConfigWebApplicationContext appContext = getContext();
    
            // Manage the lifecycle of the root application context
            container.addListener(new ContextLoaderListener(appContext));
    
            container.addListener(new Log4jConfigListener());
    
            ServletRegistration.Dynamic dispatcher = container.addServlet("DispatcherServlet", new DispatcherServlet(appContext));
            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/");
    
        }

    启动工程,控制台出现:

     其实从上面的onStarup代码中就可以看出来:

    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(appContext));

    因为ContextLoaderListener是继承ServletContextListener的。

  • 相关阅读:
    mac上python3安装HTMLTestRunner
    双目深度估计传统算法流程及OpenCV的编译注意事项
    深度学习梯度反向传播出现Nan值的原因归类
    1394. Find Lucky Integer in an Array
    1399. Count Largest Group
    1200. Minimum Absolute Difference
    999. Available Captures for Rook
    509. Fibonacci Number
    1160. Find Words That Can Be Formed by Characters
    1122. Relative Sort Array
  • 原文地址:https://www.cnblogs.com/blentle/p/7744546.html
Copyright © 2011-2022 走看看