熟悉SpringMVC的同学都知道SpringMVC的核心是DispatcherServlet(以下简称ds), 由于继承了HttpServlet, 所以它本质就是servlet, 当我们使用tomcat或其他Web容器启动项目时, 会先扫描项目的web.xml文件, 我们会在该文件中指定ds的具体路径, 并设置启动load-on-startup即加载此ds, 然后容器会自动调用ds父类中的init方法
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/spring-admin.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
public final void init() throws ServletException {
...
// 此处开始初始化
this.initServletBean();
...
}
protected final void initServletBean() throws ServletException {
...
// 开始初始化web容器
this.webApplicationContext = this.initWebApplicationContext();
// 空方法
this.initFrameworkServlet();
...
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
if(this.webApplicationContext != null) {
wac = this.webApplicationContext;
if(wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac;
if(!attrName.isActive()) {
if(attrName.getParent() == null) {
attrName.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(attrName);
}
}
}
if(wac == null) {
// 先去查找有没有已经创建的ac
wac = this.findWebApplicationContext();
}
if(wac == null) {
// 本地没有, 则创建ac, 重点
wac = this.createWebApplicationContext(rootContext);
}
if(!this.refreshEventReceived) {
// 如果没有执行refresh则调用ds的onRefresh方法, 正常情况下是有回调的, 为spring自动发起的
this.onRefresh(wac);
}
...
return wac;
}
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class contextClass = this.getContextClass();
...
// 利用反射, 调用无参数的构造函数创建对象
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
// 设置环境
wac.setEnvironment(this.getEnvironment());
wac.setParent(parent);
// 设置配置文件路径
wac.setConfigLocation(this.getContextConfigLocation());
// 执行刷新
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
...
wac.setServletContext(this.getServletContext());
wac.setServletConfig(this.getServletConfig());
wac.setNamespace(this.getNamespace());
// 向容器中注册一个监听器, 后边会用到
wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener(null)));
ConfigurableEnvironment env = wac.getEnvironment();
if(env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());
}
this.postProcessWebApplicationContext(wac);
this.applyInitializers(wac);
// 执行spring容器的初始化, 此处不做太多分析, 等解析Spring源码时再讲解
wac.refresh();
}
Spring默认会帮我们扫描到一个RequestMappingHandlerMapping类, 此类实现了ApplicationContextAware和InitializingBean接口及对应的方法, 在其被spring容器实例化,初始化并属性赋值后, 会回调对应方法afterPropertiesSet(), 然后调用父类的initHandlerMethods()方法
protected void initHandlerMethods() {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
}
// 根据类型获取所有的beanName
String[] beanNames = this.detectHandlerMethodsInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class):this.getApplicationContext().getBeanNamesForType(Object.class);
String[] var2 = beanNames;
int var3 = beanNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String beanName = var2[var4];
if(!beanName.startsWith("scopedTarget.")) {
Class beanType = null;
try {
// 从容器中获取对应的bean
beanType = this.getApplicationContext().getType(beanName);
} catch (Throwable var8) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Could not resolve target class for bean with name \'" + beanName + "\'", var8);
}
}
// 判断是否有Controller或RequestMapping注解
if(beanType != null && this.isHandler(beanType)) {
// 查找对应的method
this.detectHandlerMethods(beanName);
}
}
}
// 空方法
this.handlerMethodsInitialized(this.getHandlerMethods());
}
protected void detectHandlerMethods(Object handler) {
// 从容器中获取对应name的beanClass
Class handlerType = handler instanceof String?this.getApplicationContext().getType((String)handler):handler.getClass();
final Class userType = ClassUtils.getUserClass(handlerType);
// 将所有的带有rm注解的方法保存到map中
Map methods = MethodIntrospector.selectMethods(userType, new MetadataLookup() {
public T inspect(Method method) {
try {
// 判断方法是否有rm注解, 如果有返回, 没有返回null
return AbstractHandlerMethodMapping.this.getMappingForMethod(method, userType);
} catch (Throwable var3) {
throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var3);
}
}
});
if(this.logger.isDebugEnabled()) {
this.logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
Iterator var5 = methods.entrySet().iterator();
while(var5.hasNext()) {
Entry entry = (Entry)var5.next();
Method invocableMethod = AopUtils.selectInvocableMethod((Method)entry.getKey(), userType);
Object mapping = entry.getValue();
// 将方法注册到map中
this.registerHandlerMethod(handler, invocableMethod, mapping);
}
}
由于在spring中添加了一个监听器, 所以在容器初始化完成后会主动调用ds父类中的onApplicationEvent()方法
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
private ContextRefreshListener() {
}
public void onApplicationEvent(ContextRefreshedEvent event) {
// 调用ds类中的onRefresh方法
FrameworkServlet.this.onApplicationEvent(event);
}
}
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 各种初始化, 从Spring容器中获取对应bean并填充到当前对象中
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
至此, SpringMVC的web容器已初始化完成
由于初次阅读SpringMVC源码, 可能会有很多不足, 如有问题, 欢迎评论指正, 感激不尽!