docs/Spring全家桶/SpringMVC源码分析/DispatcherServlet初始化流程.md
һƪУͨһ demo ɹ springmvc Ӧãṩ demo У֪ tomcat ʱ MyWebApplicationInitializer#onStartup Ȼ spring ô tomcat spring أ
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 ˡ
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
DispatcherServlet#initStrategiesʼ springmvcspring ɺᷢ¼Ȼɼ 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 ʱ
HandlerMapping beanȡɹʵҲܻãѵõĽֵ DispatcherServlet handlerMappings ԣHandlerMapping ȡĬϵ HandlerMapping bean.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() ƣͲһһˡ
Ҫ springmvc ̣ܽ£
ServletContainerInitializer#onStartup springmvc ṩ SpringServletContainerInitializer ʵ֣ SpringServletContainerInitializer#onStartup ᱻãSpringServletContainerInitializer#onStartup Уspring WebApplicationInitializer#onStartup MyWebApplicationInitializer ʵ֣ MyWebApplicationInitializer#onStartup ᱻãMyWebApplicationInitializer#onStartup Ǵһ applicationContext DispatcherServlet Ȼ DispatcherServlet עᵽ servlet У tomcatDispatcherServlet עᵽ servlet У tomcat servlet ڣDispatcherServlet#init ᱻãDispatcherServlet#init лִ spring ̣spring ᷢ¼ContextRefreshListener spring ¼FrameworkServlet.ContextRefreshListener#onApplicationEvent ᱻãõõ DispatcherServlet#initStrategiesDispatcherServlet#initStrategies гʼ MultipartResolver``LocaleResolver νijʼʵǻȡӦ beanȻֵ DispatcherServlet ԡˣspringmvc ̾ˡǶûп **spring @RequestMapping **ô spring δ һƪ½
ԭӣhttps://my.oschina.net/funcy/blog/4710330 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע