• 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的。

  • 相关阅读:
    ionic中关于ionicView 的生命周期
    ES6新特性之 promise
    使用angular中ng-repeat , track by的用处
    关于前端性能优化的思考
    浅谈JavaScript之原型
    浅谈JavaScript的New关键字
    JavaScript中闭包之浅析解读
    python3 linux下安装
    mycat高可用方案
    mysql高可用方案
  • 原文地址:https://www.cnblogs.com/blentle/p/7744546.html
Copyright © 2020-2023  润新知