美文网首页spring
spring mvc的启动过程分析(1)

spring mvc的启动过程分析(1)

作者: c7d122ec46c0 | 来源:发表于2017-09-09 21:51 被阅读0次

基于java文件的spring mvc配置

spring 3.2 引入了一个AbstractAnnotationConfigDispatcherServletInitializer实现了WebApplicationInitializer 接口,继承这个类可以替代web.xml的作用,spring也推荐使用基于java文件做spring配置。下面是spring 官网的一个配置

    public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

        @Override
        protected Class<?>[] getRootConfigClasses() {
            // GolfingAppConfig defines beans that would be in root-context.xml
            return new Class[] { GolfingAppConfig.class };
        }

        @Override
        protected Class<?>[] getServletConfigClasses() {
            // GolfingWebConfig defines beans that would be in golfing-servlet.xml
            return new Class[] { GolfingWebConfig.class };
        }

        @Override
        protected String[] getServletMappings() {
            return new String[] { "/golfing/*" };
        }

    }

一张spring文档中的图

image.png

web容器在启动过程中如何找到WebApplicationInitializer

以tomcat为例子,tromcat在启动时会调用StandardContext.java的startInternal()方法,这个方法会去查找所有实现了 ServletContainerInitializer接口的类。SpringServletContainerInitializer实现了ServletContainerInitializer,SpringServletContainerInitializer又会去寻找实现了WebApplicationInitializer接口的类,这样就成功找到了。
贴上部分源码

StandardContext的startInternal()方法

    for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
            initializers.entrySet()) {
            try {
                 //调用SpringServletContainerInitializer的onStartup方法
                entry.getKey().onStartup(entry.getValue(),
                        getServletContext());
            } catch (ServletException e) {
                log.error(sm.getString("standardContext.sciFail"), e);
                ok = false;
                break;
            }
        }

SpringServletContainerInitializer 的onStartup 方法

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) {
    // 调用实现了WebApplicationInitializer接口的onStartup方法
            initializer.onStartup(servletContext);
        }
    }

Spring mvc 实现了WebApplicationInitializer接口的类

image.png

AbstractDispatcherServletInitializer的onStartup方法

@Override
    public void onStartup(ServletContext servletContext) throws ServletException {
                //ContextLoaderListener初始化,实例化IoC容器,并将此容器实例注册到ServletContext中;
                super.onStartup(servletContext);
                //DispatcherServlet初始化
            registerDispatcherServlet(servletContext);
    }

Root WebApplicationContext的初始化

上段代码中super.onStartup(servletContext)实现 Root WebApplicationContext的初始化

@Override
    protected WebApplicationContext createRootApplicationContext() {
        Class<?>[] configClasses = getRootConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(configClasses);
            return rootAppContext;
        }
        else {
            return null;
        }
    }

AbstractContextLoaderInitializer的 registerContextLoaderListener 方法

protected void registerContextLoaderListener(ServletContext servletContext) {
        WebApplicationContext rootAppContext = createRootApplicationContext();
        if (rootAppContext != null) {
            ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
            listener.setContextInitializers(getRootApplicationContextInitializers());
            //在web容器的servletcontext中添加ContextLoaderListener,监听web容器初始化
            // web容器初始化时初始化Root WebApplicationContext,详见第一张图
            servletContext.addListener(listener);
        }
        else {
            logger.debug("No ContextLoaderListener registered, as " +
                    "createRootApplicationContext() did not return an application context");
        }
    }

Root WebApplicationContext 在tomcat 调用listenerStart方法 时初始化Root WebApplicationContext

关于Servlet WebApplicationContext的分析以后在做吧

参考
22. Web MVC framework
深入分析Spring 与 Spring MVC容器
Spring源码分析【3】-SpingWebInitializer的加载
tomcat实现ServletContext的addListener方法的源码解说(原创)
SpringMVC启动过程详解(li)

相关文章

网友评论

    本文标题:spring mvc的启动过程分析(1)

    本文链接:https://www.haomeiwen.com/subject/mpfgjxtx.html