Back to Javatutorial

DispatcherServlet初始化流程

docs/Spring全家桶/SpringMVC源码分析/DispatcherServlet初始化流程.md

1.0.015.4 KB
Original Source

һƪУͨһ򵥵 demo ɹ springmvc Ӧãṩ demo У֪ tomcat ʱ MyWebApplicationInitializer#onStartup Ȼ spring ô tomcat spring أ

1. servlet ʼDispatcherServlet#init

ٻ MyWebApplicationInitializer#onStartup

@Override
public void onStartup(ServletContext servletContext) {
   System.out.println("webApplicationInitializer ...");
   //  spring  applicationContext
   AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
   context.register(MvcConfig.class);

   // ʵ DispatcherServlet
   DispatcherServlet servlet = new DispatcherServlet(context);

   // DispatcherServletעᵽservlet
   ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
   registration.setLoadOnStartup(1);
   registration.addMapping("/*");
}

δ׼һ AnnotationConfigWebApplicationContextΪ DispatcherServlet УȻ servlet DispatcherServletservlet ʱͻ spring ˡҪľ DispatcherServletǾ servlet.

DispatcherServlet ļ̳нṹ

ͼԿspring ṩġ servlet صHttpServletBean``FrameworkServlet DispatcherServletΪ servlet֪ʼΪ GenericServlet#init()Ҳ servlet ڷǵķҲ↑ʼ

DispatcherServlet ʵ HttpServletBean``FrameworkServlet``DispatcherServlet#init() ʵϼ̳ HttpServletBean#init

@Override
public final void init() throws ServletException {

    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            ...
        }
    }

    // ʼ servlet beanspringþе
    initServletBean();
}

ԿһЩãȻ͵ initServletBeanûһЩ spring ʵԵݡǼвҪķ·£

-HttpServletBean#init
 -FrameworkServlet#initServletBean
  -FrameworkServlet#initWebApplicationContext

һֱ FrameworkServlet#initWebApplicationContext

protected WebApplicationContext initWebApplicationContext() {
    // ȡΪWebServerApplicationContextĸõĽΪnull
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
        // webApplicationContextMyWebApplicationInitializer#onStart
        // AnnotationConfigWebApplicationContext
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                    cwac.setParent(rootContext);
                }
                //  AbstractApplicationContext#refresh 
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    // wacΪnull,ﲻ
    if (wac == null) {
        wac = findWebApplicationContext();
    }
    // wacΪnull,ﲻ
    if (wac == null) {
        // WebApplicationContextAbstractApplicationContext#refresh
        wac = createWebApplicationContext(rootContext);
    }

    // ʵϣrefreshEventReceivedΪtrueifĴ벢ִ
    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            // ˢӦģspringmvcش
            onRefresh(wac);
        }
    }

    if (this.publishContext) {
        //  WebApplicationContextΪservletContext һԣ뵽 servletContext 
        // ֮Ϳʹ
        // WebApplicationContextUtils.getWebApplicationContext(ServletContext, String attrName)
        // ȡ
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }

    return wac;
}

زעͣʵ ҪĴΪ

protected WebApplicationContext initWebApplicationContext() {
    ...
    //  AbstractApplicationContext#refresh 
    configureAndRefreshWebApplicationContext(cwac);
    ...
    return wac;
}

ط£

FrameworkServlet#configureAndRefreshWebApplicationContext

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        if (this.contextId != null) {
            wac.setId(this.contextId);
        }
        else {
            // Generate default id...
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(getServletContext().getContextPath()) + 
                    '/' + getServletName());
        }
    }
    wac.setServletContext(getServletContext());
    wac.setServletConfig(getServletConfig());
    wac.setNamespace(getNamespace());
    // ¼spring¼
    // ʮҪ
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    }
    // չ㣬ûʲôܣԺչ
    postProcessWebApplicationContext(wac);
    applyInitializers(wac);
    // þ AbstractApplicationContext.refresh
    wac.refresh();
}

ʵϻ ConfigurableWebApplicationContext һЩԣ AbstractApplicationContext#refresh spring AbstractApplicationContext#refresh ķԲο spring ֮ǰ׼

spring ˡ

2. SourceFilteringListener¼

и⣺ springmvc У֪ spring ʶ @Controller RequestMapping/@PostMapping/@GetMapping עе·װΪһ uriȴⲿʣһ·ƺ spring ûЩôⲿֵĹеأ

ʵϣspring ⲿֵĹɵģҲ

wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

spring ¼ spring ɺá

spring ¼ݣԲο spring ֮̽ spring ¼ֱ˵ۣspring ṩ ApplicationEventPublisher#publishEvent(Object)¼ApplicationEvent¼ ApplicationListener ¼ spring ͨ ApplicationEventPublisher#publishEvent(Object) ApplicationEvent¼ʱApplicationListener ¼

SourceFilteringListener

public class SourceFilteringListener implements GenericApplicationListener, SmartApplicationListener {

    private final Object source;

    @Nullable
    private GenericApplicationListener delegate;

    /**
     * 췽 event  listener
     */
    public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
        this.source = source;
        this.delegate = (delegate instanceof GenericApplicationListener ?
                (GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
    }

    /**
     * ¼
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event.getSource() == this.source) {
            // ¼
            onApplicationEventInternal(event);
        }
    }

    /**
     *  ¼
     */
    protected void onApplicationEventInternal(ApplicationEvent event) {
        if (this.delegate == null) {
            throw new IllegalStateException(...);
        }
        // ջǵô¼onApplicationEvent
        this.delegate.onApplicationEvent(event);
    }

    // ʡһЩ
    ...

ԿSourceFilteringListener ͨ췽 ContextRefreshListener ʵȻ SourceFilteringListener#onApplicationEvent Уյõ ContextRefreshListener#onApplicationEvent

ContextRefreshListener

FrameworkServlet.ContextRefreshListener

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        FrameworkServlet.this.onApplicationEvent(event);
    }
}

FrameworkServlet ڲܼ࣬򵥣յõ FrameworkServlet#onApplicationEvent

public void onApplicationEvent(ContextRefreshedEvent event) {
    // ޸״̬ܹؼк
    // FrameworkServlet#initWebApplicationContextonRefresh(...)Ͳ
    this.refreshEventReceived = true;
    synchronized (this.onRefreshMonitor) {
         // ߼
         onRefresh(event.getApplicationContext());
    }
}

DispatcherServlet#onRefresh ˣ

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

/**
 * springmvcռؾ
 * Уʼspringmvcĸ
 */
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

Կеķ DispatcherServlet#initStrategiesֻУҳʼ springmvc

3. DispatcherServlet#initStrategiesʼ springmvc

spring ɺ󣬻ᷢ¼Ȼɼ SourceFilteringListener ¼ִм߼յõ DispatcherServlet#initStrategiesǽ DispatcherServlet#initStrategies ִй̡

ʵܼ򵥣 9 д룬ÿд붼ʼ springmvc һ initMultipartResolver

public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";

private void initMultipartResolver(ApplicationContext context) {
    try {
        // springлȡmultipartResolver
        this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
    }
    catch (NoSuchBeanDefinitionException ex) {
        // ȡʧܣĬΪnull
        this.multipartResolver = null;
        }
    }
}

multipartResolver ļϴ bean spring УǴļϴʱһ multipartResolver bean

@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setDefaultEncoding("UTF-8");
    resolver.setResolveLazily(true);
    resolver.setMaxInMemorySize(40960);
    //ϴļΪ1G
    resolver.setMaxUploadSize(1024 * 1024 * 1024);
    return resolver;
}

δ multipartResolver beanspring ĬΪ nullͲܽļϴˡ

springmvc HandlerMappings ijʼ̣

DispatcherServlet

public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

private static final Properties defaultStrategies;

static {
    try {
        // staticмDispatcherServlet.propertiesļ
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, 
                DispatcherServlet.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException(...);
    }
}

/**
 * handlerMappings 
 */
@Nullable
private List<HandlerMapping> handlerMappings;

/**
 * ʼ HandlerMappings
 * 1\. spring лȡ HandlerMapping bean
 *     ȡɹѵõĽֵhandlerMappings
 * 2\. δãȡĬϵ HandlerMapping bean
 */
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    if (this.detectAllHandlerMappings) {
        // ʵHandlerMappingӿڵbean
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        // ﲻΪգ
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // SpringǸĽд
            // ǰhandlerMappingԴ׸һ
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }
    if (this.handlerMappings == null) {
        // δhandlerMappingsȡĬϵ handlerMappings
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    }
}

/**
 * ȡĬϵIJ
 */
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    // ȡļDispatcherServlet.propertiesĬϵ class 
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            try {
                // ʹ÷䴴bean
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                Object strategy = createDefaultStrategy(context, clazz);
                strategies.add((T) strategy);
            }
            catch (ClassNotFoundException ex) {
                throw new BeanInitializationException(...);
            }
            catch (LinkageError err) {
                throw new BeanInitializationException(...);
            }
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}

ʼ HandlerMappings ʱ

  1. ȴ spring лȡ HandlerMapping beanȡɹʵҲܻãѵõĽֵ DispatcherServlet handlerMappings ԣ
  2. δʧܣ spring δ HandlerMapping ȡĬϵ HandlerMapping bean.
  3. ȡĬϵ HandlerMapping bean ʱȡ DispatcherServlet.properties ãȻʹ÷ʵ

DispatcherServlet.properties ļļλ spring-webmvc/src/main/resources/org/springframework/web/servlet/DispatcherServlet.properties£

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
    org.springframework.web.servlet.function.support.RouterFunctionMapping
...

DispatcherServlet#initStrategies initXxx() ƣͲһһˡ

4. ܽ

Ҫ springmvc ̣ܽ£

  1. servlet tomcatʱͨ spi ִ ServletContainerInitializer#onStartup springmvc ṩ SpringServletContainerInitializer ʵ֣ SpringServletContainerInitializer#onStartup ᱻã
  2. SpringServletContainerInitializer#onStartup Уspring WebApplicationInitializer#onStartup MyWebApplicationInitializer ʵ֣ MyWebApplicationInitializer#onStartup ᱻã
  3. MyWebApplicationInitializer#onStartup Ǵһ applicationContext 󣬽 DispatcherServlet 󶨣Ȼ DispatcherServlet עᵽ servlet У tomcat
  4. DispatcherServlet עᵽ servlet У tomcat󣬸 servlet ڣDispatcherServlet#init ᱻã
  5. DispatcherServlet#init лִ spring ̣spring 󣬻ᷢ¼
  6. spring ɺContextRefreshListener spring ¼FrameworkServlet.ContextRefreshListener#onApplicationEvent ᱻãõõ DispatcherServlet#initStrategies
  7. spring DispatcherServlet#initStrategies гʼ MultipartResolver``LocaleResolver νijʼʵǻȡ򴴽Ӧ beanȻֵ DispatcherServlet ԡ

ˣspringmvc ̾ˡǶûп **spring @RequestMapping **ô spring δ һƪ½


ԭӣhttps://my.oschina.net/funcy/blog/4710330 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע