1. dispatcherServlet
1.1 DispatcherServlet 介绍
DispatcherServlet 是 HTTP 请求 的 处理器(handlers)和 控制器(controllers) 的 中央调度者,例如 web UI controller,或者是 其他的基于 Http 远程服务。调度已注册的 处理器 可以处理请求,提供方便的映射 以及 异常的处理组件。
这个 servlet 非常的灵活:
搭配 合适的 适配器(adapter)类,可以用于几乎任何工作流,提供了以下区别于 其他 请求驱动的(request-driven)的 web mvc 框架 的 功能:
★ 它是基于 javaBean 配置文件 机制;
★dispatcherServlet 可以使用 任何的 HandlerMapping 实现类(预构建或者是作为应用的部分提供,用来控制请求到处理器(handler)对象的路由) 。默认使用以下两个实现类(见 Spring jar 包中的 DispathcerServlet.properties)
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
自定义的 HandlerMapping 对象( 实现 HandlerMapping 接口,覆盖默认的方法) 可以作为 bean 定义在 Servlet 的 应用上下文中。并且这个 bean 的名称可以自定义(因为 他们是通过 类型 来 查找的)
★ 可以 使用 任何 HandlerAdapter(处理器适配器);这就允许 使用任何 处理器(handler)接口。
默认的 适配器(adapter):
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
spring 的
org.springframework.web.HttpRequestHandler
org.springframework.web.servlet.mvc.Controller
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
以上配置都会被注册,handlerAdapter 对象 可以被作为 bean 添加到 应用上下文中,重写默认的 HandlerAdapter,和 HandlerMapping 一样,HandlerAdapter 的 bean 名称可以随意;
★ dispatcher 的异常 处理 机制 可以 通过 HandlerExceptionResolver 指定;例如映射指定的异常到错误页。
★ 视图 处理 机制 可以 通过 ViewResolver 的 实现类 指定,把 视图 名称 解析为 视图对象。默认的视图 解析器(resolver) 是
org.springframework.web.servlet.view.InternalResourceViewResolver
ViewResolver 对象 可以 作为 bean 添加 到 应用上下文中,重写 默认的 ViewResolver。ViewResolver 的 bean 名称 可以 随意。
★ 如果用户 并没有 提供 一个 View 对象 或者 视图名称,那么 就会使用 RequestToViewNameTranslator 对象 将当前的 请求 翻译成 视图名称
★ 解析 multipart 请求 的调度策略 是由 以下接口的实现类 决定的
org.springframework.web.multipart.MultipartResolver
包括了 Apache Commons FileUpload 的实现类和 Servlet 3相关的实现类;一般性选择 是 FileUpload 的实现类
org.springframework.web.multipart.commons.CommonsMultipartResolver
MultipartResolver 的 bean 名称 是 multipartResolver;没有 配置 默认的 multipartResolver 实现类,所以需要 自己配置
★ 区域 处理机制 是由 LocaleResolver 接口 决定的,LocalResolver bean 名称是 localResolver ,默认 配置的 解析器是
org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
★ 主题处理策略 是由 ThemeResolver 接口 决定的 ,实现了一个固定的主题(theme)以及 cookie 和 session 的存储, ThemeResolver 的 bean 名称 为 themeResolver , 默认配置的 是
org.springframework.web.servlet.theme.FixedThemeResolver
一个 web 应用 可以 定义 任意多个 DispatcherServlet ,每个 Servlet 只在自己的 命名空间中操作,使用 映射(mapping) 和 处理器(handler)加载 自己 的 应用上下文.
仅仅当 根 应用上下文 被 ContextLoaderListener 加载时 , 这个 根 应用上下文 将会 被 所有的 DispatcherServlet 共享
1.2 DispatcherServlet 关系
分析:
Aware :标记型 超类, 表明 一个 bean 需要 被 Spring 容器 的 某个 框架对象 通过 一个回调的方法 通知。 通常通过子接口 决定 ,通常是一个 无返回值并且含有一个 参数的方法。
例如 其子接口 ApplicationContextAware 接口:实现该接口的对象 是希望 感知到 运行在其中的 ApplicationContext 。进而通过 ApplicationContext 获取到已加载的 各种 bean。
ApplicationContextAware 接口源码:
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
代码示例(其他 aware 接口使用同理):
@Service
public final class SpringContext implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
public static <T>T getBean(String beanName , Class<T>clazz) {
return applicationContext.getBean(beanName , clazz);
}
}
Servlet : Java EE 的 servlet api ,顶层父类,其中的抽象方法如下(代表了其生命周期):
void init(ServletConfig config); //Serlet 实例化之后由 Servlet 容器调用 ,只调用一次
ServletConfig getServletConfig(); //返回 初始化和启动参数,返回的是init 方法中传递的那个对象
void service(ServletRequest req, ServletResponse resp); // 响应请求, 通常运行在多线程的 Servlet 容器中
String getServletInfo(); //返回 servlet 的作者,版本,版权等信息
void destroy();
servlet api 中提供了两种抽象实现类 GenericServelt(通用的,与协议无关的 Servlet) 以及 HttpServlet(http 协议的 Servlet),如果设置了 load-on-startup 则在 应用启动的时候调用 init 方法初始化,否则在第一次调用的时候初始化。(filter 在应用启动的时候初始化,始终在 servlet 之前初始化。listener 始终在 filter 之前初始化)
Spring 中的 抽象 和 实现:
HttpServletBean:将 Servlet 的 配置参数(Servlet标签中 init-param 标签的配置)置为内置的 bean属性
FrameworkServlet:Spring web框架的基础 Servlet, 和 Spring 的 ApplicationConext(应用上下文)进行了整合,该类提供了如下功能:
★ 管理每个 Servlet 的 WebApplicationContext, Servlet 的配置文件是由 Servlet 命名空间中的 bean 决定的
★ 无论一个请求是否成功处理都会 发布 请求处理的事件
在 Servlet 初始化时,检测 一个叫 contextClass 的参数,如果没有声明该参数,则使用默认的 XmlWebApplicationContext.
这里注意,使用默认的 FrameworkServlet,如果使用自定义的 contextClass,则必须实现 ConfigurableWebApplicationContext:
比如 Spring 提供的基于java 代码配置的 AnnotationConfigWebApplicationContext;
接收一个contextInitializerClasses 的初始化参数(init-param)
接收一个 contextConfigLocation 的初始化参数(init-param)
DispatcherServlet:需要配置的 servlet
DispatcherServlet 配置案例:
<servlet>
<servlet-name>mybatis</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.ycit.config.MvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mybatis</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2. DispatcherServlet 初始化 源码流程解析(基于 spring 4.3.14)
首先从 Servlet 的 初始化方法 init开始:
Spring 中 HttpServletBean 类重写了 init 初始化方法(load-on-startup 设置则 启动时调用init 方法,否则第一次请求调用的时候调用 init 方法)。
————————HttpServletBean init() 方法 begin——————:
/**
* 将 该 servlet 的 配置参数 映射到 bean 属性上
* 同时 调用子类继续初始化
*/
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
//将servlet初始化参数 设置到 bean 配置中
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) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// 由子类 FrameworkServlet 重写继续初始化
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
相关类说明:
PropertyValues:持有 一个 或者 多个 PropertyValue 对象的 容器。
—— PropertyValue: 保存 单个 bean 属性 的 信息 和 值 的 对象 ,就是一个 POJO 类。主要字段为 name 和 value
—— ServletConfigPropertyValues: PropertyValues 在 HttpServletBean类 中的一个内部实现类,从 ServletConfig 的初始化参数 中 获取 必要信息,只包含了一个构造函数,直接父类为 MutablePropertyValues ,MutablePropertyValues 为PropertyValues 的 默认实现类。
ServletConfigPropertyValues 构造函数:
/**
* 构造函数
* @param config 包含初始化参数的 ServletConfig
* @param requiredProperties 必须要配置的属性
*/
public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
throws ServletException {
Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
new HashSet<String>(requiredProperties) : null);
Enumeration<String> paramNames = config.getInitParameterNames();//获取配置的初始化参数
while (paramNames.hasMoreElements()) {
String property = paramNames.nextElement();
Object value = config.getInitParameter(property);
addPropertyValue(new PropertyValue(property, value));//调用父类中的方法添加属性
if (missingProps != null) {
missingProps.remove(property);
}
}
// 如果必须的属性没有配置则抛出异常
if (!CollectionUtils.isEmpty(missingProps)) {
throw new ServletException(
"Initialization from ServletConfig for servlet '" + config.getServletName() +
"' failed; the following required properties were missing: " +
StringUtils.collectionToDelimitedString(missingProps, ", "));
}
}
以上代码 主要作用是 读取 Servlet 中的 配置参数。
相关方法说明:
initServletBean 方法:由子类 FrameworkServlet 重写,完成FrameworkServlet 需要完成的任务.
————————————————————————initServletBean 方法begin
FrameworkServlet 类 的 initServletBean 方法:主要是初始化 web 应用上下文,并加载配置。
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext(); // 初始化 web 应用上下文
initFrameworkServlet(); // 提供子类自定义实现的方法,类似 该 initServletBean 方法
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
initServletBean方法 中的 initWebApplicationContext 方法:
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext()); // 获取根应用上下文,即 ContextLoaderListener 加载的 web 应用上下文
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);
}
configureAndRefreshWebApplicationContext(cwac); // 配置 bean 并且刷新 web 应用上下文
}
}
}
if (wac == null) {
wac = findWebApplicationContext();// servelt 上下文中是否 注入了 web 应用上下文
}
if (wac == null) {
wac = createWebApplicationContext(rootContext); // 创建一个 web 应用上下文
}
if (!this.refreshEventReceived) {.
onRefresh(wac); // 刷新 web 应用上下文
}
if (this.publishContext) {
//将 web 应用上下文发布到 Servlet 的 上下文中.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
initWebApplicationContext 方法 中的 createWebApplicationContext 方法:
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
} // 实例化 web 应用上下文
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac); // 配置并刷新 web 应用上下文
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
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());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));//添加 监听器
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh(); // 这里 和 ContextLoaderListener 初始化时一致
}
相关类说明:
SourceFilteringListener: ApplicationListener 的装饰类,用于从指定的事件源中过滤事件,然后为 匹配的 ApplicationEvent 对象 调用委托的监听器
——直接父类 GenericApplicationListener : ApplicationListener 接口的 扩展类,暴露更多的源数据,例如支持的事件类型。spring 4.2 中 替代 SmartApplicationListener . 正确处理 基于 事件的泛型。
——父类 ApplicationListener:实现了 java.util.EventListener 接口,是 基于标准的 EventListener 接口 的 观察者设计模式。jdk 中规定 所有 的 事件 监听接口 都必须继承 EventListener.EventListener 只是一个 标记型接口。
—— 监听的事件 ApplicationEvent :所有的应用事件都要继承的抽象类,父类 EventObject 是 jdk 中 所有事件 对象的根类。所有的事件 都是由 一个 对象的 引用 ,即 “source” 来 构造的,它代表了事件最初发生的对象。
ContextRefreshListener:FrameworkServlet 的内部实现类,实现了 ApplicationListener 接口,只从 Servelt 的 WebApplicationContext 中 接收 事件,然后再调用 FrameworkServlet 实例 的 onApplicationEvent 方法。
——相关的事件 ContextRefreshEvent:FrameworkServlet 的内部实现类。当 ApplicationContext 初始化 并且 刷新 时引发的事件。直接父类 ApplicationContextEvent, ApplicationContext 引发的事件。
ConfigureAndRefreshWebApplicationContext 方法中调用的 SourceFilteringListener 构造函数
/**
* @param source 该监听器 过滤的事件源,仅仅处理来自该 源对象的事件,
* @param delegate 委托 从指定 源 调用 事件的 监听器
*/
public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
this.source = source;
this.delegate = (delegate instanceof GenericApplicationListener ?
(GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
}
上面使用了 适配器设计模式来适配 监听器,此时传入的 delegate 为 ContextRefreshListener,不是 GenericApplicationListener 的 子类,需要使用适配器 GenericApplicationListenerAdapter。
ConfigureAndRefreshWebApplicationContext 中调用 WebApplicationContext 的 addApplicationListener 方法:
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
else {
this.applicationListeners.add(listener);
}
}
/** 监听器暂存 */
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/** 增删监听器,发布事件等的帮助类 */
private ApplicationEventMulticaster applicationEventMulticaster;
相关类说明:
ApplicationEventMulticaster:实现该接口的对象 可以管理 监听器(增加 和删除),也可以被 应用上下文 委托来 发布事件。作用类似于 观察者模式中的 Obserable .
ConfigureAndRefreshWebApplicationContext 调用 AbstractApplicationContext 的 refresh 方法:主要就是为 web 应用上下文 进行配置,在 解析 ContextLoaderListener 源码的时候,也是走的这个代码。详情参看 ContextLoaderListener 源码解析。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// 统一管理事件发布,为下面的注册监听器做准备
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// 这里会将上面添加到 applicationListener 字段的监听器
//注册到 ApplicationEventMulticaster 中,类似观察者中的 Observerable 的职能
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 发布相关事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
refresh 方法中调用的 registerListeners 方法:将监听器 添加到 web 应用上下文的 applicationEventMulticaster 属性中管理:
protected void registerListeners() {
// 将 applicationListeners 集合 中的监听器 添加到 ApplicationEventMulticaster 的实现类中.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布 earlyApplicationEvents 中的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
/**
* Return the list of statically specified ApplicationListeners.
*/
public Collection<ApplicationListener<?>> getApplicationListeners() {
return this.applicationListeners;
}
refresh 方法中调用的 finishRefresh 方法:把之前加入管理的事件 发布。
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// 发布 事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
publishEvent 方法中最终调用 doInvokeListener 方法————————发布事件 begin:
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用 监听器的 onApplicationEvent 方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
doInvokeListener 方法中的 onApplicationEvent 方法:SourceFilteringListener 中的方法,SourceFilteringListener的deletgate 为 GenericApplicationListenerAdapter,因为 ContextRefreshListener 不是 GenericApplicationListener 的子类,需要采用适配器:
@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(
"Must specify a delegate object or override the onApplicationEventInternal method");
}
this.delegate.onApplicationEvent(event);
}
所以 调用 GenericApplicationListenerAdapter 的 onApplicationEvent 方法:delegate 为 ContextRefreshListener
@Override
public void onApplicationEvent(ApplicationEvent event) {
this.delegate.onApplicationEvent(event);// delegate 为 ContextRefreshListener
}
ContextRefreshListener 的 方法:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
类名.this 在 java 中被 定义为 Qualified this ,一般是在内部类中使用,用来访问外层对象实例。这里用来访问 FrameworkServlet 实例。
FrameworkServlet 的 onApplicationEvent 方法:
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
onRefresh(event.getApplicationContext());
}
// 由子类 DispatcherServlet 重写
protected void onRefresh(ApplicationContext context) {
// For subclasses: do nothing by default.
}
DispatcherServlet 的 onRefresh 方法:初始化一些 策略对象
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
// 初始化 策略对象
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //默认不配置 multiResolver,如果使用的话需要开发者自行定义
initLocaleResolver(context); //默认配置 AcceptHeaderLocaleResolver
initThemeResolver(context); // 默认配置FixedThemeResolver
initHandlerMappings(context); //默认配置2个
initHandlerAdapters(context); //默认配置3个
initHandlerExceptionResolvers(context); //默认配置3个
initRequestToViewNameTranslator(context); //默认配置 DefaultRequestToViewNameTranslator
initViewResolvers(context); // 使用默认的 InternalResourceViewResolver,但是进行了自定义。
initFlashMapManager(context); //默认配置SessionFlashMapManager
}
这里主要看一下 initHandlerMappings 方法:初始化 处理器映射,其他的初始化大体相似
/**
* 如果在 BeanFactory 中没有 定义 HandlerMapping
* 将会使用 默认的 BeanNameUrlHandlerMapping
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
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.
}
}
//没有发现配置的HandlerMapping ,使用默认的 BeanNameUrlHandlerMapping
// 以及 DefaultAnnotationHandlerMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
这些使用的默认的配置均在 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.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
至此 ——————————事件发布结束。
initWebApplicationContext 结束 ,完成了所有需要配置 和动作。
initFrameworkServlet 方法 目前为 空方法, DispatcherServlet 没有进行 重写。
至此 —————————————————————— initServletBean 方法 结束。
DispatcherServlet 初始化结束。
DispatcherServlet 工作流程:
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。