前言
在进入springmvc源码之前,我们应该知道的是,Servlet的生命周期。
实例化(调用空的构造函数)—初始化(init方法)—调用Service方法(调用doService方法)–销毁(destory方法)
初始化方法和销毁方法,只会调用一次,在我们初始化Servlet的时候调用init方法,销毁容器之前会调用destory方法。所以,我们在进入DispatcherServlet之前,应该可以猜得到,他或者他的父类应该会有这样一个方法。最终我们发现,GenericServlet这个抽象类,找到init方法,但这是一个空实现,肯定要交给子类去覆写。

覆写了init方法的类。

上面一图是DispatcherServlet的继承结构树。自然,我们需要找的实现了init方法的类就是HttpServletBean,那我们就从这里看起。
初始化DispatcherServlet
public final void init() throws ServletException {
//将web.xml中的<param-value>classpath:spring-mvc.xml</param-value>读取解析,存入到this.requiredProperties中
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
//将需要包装的DispatcherServlet对象包装成一个BeanWrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//将spring-mvc.xml加载成一个资源装载器
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
} catch (BeansException var4) {
if (this.logger.isErrorEnabled()) {
this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
}
throw var4;
}
}
this.initServletBean();
}
从web.xml中拿到paramValue属性之后,存放到一个叫requiredProperties的属性中。然后拿到一个包装类,其实bw这个包装类,就是包装了DispatcherServlet。然后将我们的spring-mvc.xml文件加载成一个资源装载器。下面就是给bw这个对象设置一些属性。最后会去调用initServletBean。这个方法在本类中其实也是一个空实现,交给FrameworkServlet这个子类去实现。
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("Initializing Servlet '" + this.getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (RuntimeException | ServletException var4) {
this.logger.error("Context initialization failed", var4);
throw var4;
}
if (this.logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data";
this.logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value);
}
if (this.logger.isInfoEnabled()) {
this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
在进行了一些日志的操作之后,记录一下开始的时间,我们会去进行初始化一个ApplicationContext。
protected WebApplicationContext initWebApplicationContext() {
//获取web容器
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
//在父容器中找
if (wac == null) {
wac = this.findWebApplicationContext();
}
if (wac == null) {
wac = this.createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
synchronized(this.onRefreshMonitor) {
this.onRefresh(wac);
}
}
if (this.publishContext) {
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
}
return wac;
}
首先去获取web容器,我们在之前是没有设置过的,所以获取到的是null,然后再去父容器中找,找到不到依然为null。那么接下来就要去创建一个WebApplicationContext了。
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
//拿到ApplicationContext的类型
Class<?> contextClass = this.getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
} else {
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(this.getEnvironment());
wac.setParent(parent);
String configLocation = this.getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
那么创建的这个ApplicationContext的类型到底是什么类型呢。
public Class<?> getContextClass() {
return this.contextClass;
}
public FrameworkServlet() {
this.contextClass = DEFAULT_CONTEXT_CLASS;
this.contextInitializers = new ArrayList();
this.publishContext = true;
this.publishEvents = true;
this.threadContextInheritable = false;
this.dispatchOptionsRequest = false;
this.dispatchTraceRequest = false;
this.enableLoggingRequestDetails = false;
this.webApplicationContextInjected = false;
this.refreshEventReceived = false;
this.onRefreshMonitor = new Object();
}
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
这里我们就很清楚的可以看到,其实它默认创建的是一个XmlWebApplicationContext。拿到这个类型之后,就会去通过反射去创建这个实例了。创建完成之后,去给他设置一些属性,有父容器设置父容器,再去调用configureAndRefreshWebApplicationContext这个方法。配置和刷新WebApplicationContext。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (this.contextId != null) {
wac.setId(this.contextId);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + '/' + this.getServletName());
}
}
wac.setServletContext(this.getServletContext());
wac.setServletConfig(this.getServletConfig());
wac.setNamespace(this.getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
}
this.postProcessWebApplicationContext(wac);
this.applyInitializers(wac);
wac.refresh();
}
前面就没有什么好说的,设置一些参数,但是在最后,看到一个熟悉的方法,refresh。其实初始化DispatcherServlet的时候,是基于事件派发机制实现的。进入到refresh这个方法之后。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//容器刷新之前初始化一些参数
this.prepareRefresh();
//创建beanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//给beanFactory设置一些参数
this.prepareBeanFactory(beanFactory);
try {
//空方法,交给子类扩展
this.postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostProcessor
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册BeanPostProcessors
this.registerBeanPostProcessors(beanFactory);
//国际化的一些操作
this.initMessageSource();
//初始化一些时间多播器
this.initApplicationEventMulticaster();
空方法,交给子类扩展
this.onRefresh();
//注册监听器
this.registerListeners();
//初始化一些单实例非懒加载的bean实例
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
由于侧重点不同,我们需要关注的是finishRefresh。

在这个方法中,注册了ContextRefreshedEvent这样一个事件,我们进入到publishEvent这里。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
Object applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent)event;
} else {
applicationEvent = new PayloadApplicationEvent(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
在进行了一些赋值的操作之后,判断一下一些早期事件是否为null,因为我们此前并没有对此进行操作,所以肯定是为null。然后拿到事件的多播器之后,就会进行事件的发布了。

这个方法中,会调用invokeListener来回调监听方法。


继续进入到这个方法中,回调onApplicationEvent方法。

但是,ApplicationListener接口中的方法,别很多子类所重写,那么到底是哪个呢,我们上面提到,我们注册了ContextRefreshedEvent这样一个事件,那自然需要用ContextRefreshListener去监听。

我们DeBug后发现,确实会进入到这样的一个方法。值得注意的是,这个ContextRefreshListene其实是FrameworkServlet的一个内部类,在这个方法中,他回去调用FrameworkServlet类中的一个onApplicationEvent方法。

然后再去调用一个onfresh方法。

这样,就已经进入了DispatcherServlet当中了,并且在initStrategies这个方法中初始化DispatcherServlet的各种属性。该方法调用了DispatcherServlet内部的9个初始化方法,分别初始化不同的组件。此方法结束之后,DispatcherServlet就已经初始化完毕了。
protected void initStrategies(ApplicationContext context) {
// 初始化文件上传解析器
initMultipartResolver(context);
// 本地化解析
initLocaleResolver(context);
// 主题解析器
initThemeResolver(context);
// 处理器映射器 保存Url映射关系
initHandlerMappings(context);
// 处理器适配器
initHandlerAdapters(context);
// 异常解析器
initHandlerExceptionResolvers(context);
// 视图提取器,从request中获取viemName
initRequestToViewNameTranslator(context);
// 视图解析器
initViewResolvers(context);
// 参数解析器
initFlashMapManager(context);
}
352

被折叠的 条评论
为什么被折叠?



