Spring 源码解析之DispatcherServlet源码解析(五)
前言
本文需要有前四篇文章的基础,才能够清晰易懂,有兴趣可以先看看详细的流程,这篇文章可以说是第一篇文章,也可以说是前四篇文章的的汇总,Spring的整个请求流程都是围绕着
DispatcherServlet
进行的
类结构图
根据类的结构来说DispatcherServlet本身也是继承了HttpServlet的,所有的请求都是根据这一个Servlet来进行转发的,同时解释了为什么需要在web.xml进行如下配置,因为Spring是基于一个Servlet来展开的,当然不需要Servlet也能够使用Spring
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
1 DispatcherServlet初始化
1.1 DispatcherServlet初始化加载的几个bean
protected void initStrategies(ApplicationContext context) {
//初始化文件上传处理类
initMultipartResolver(context);
//初始化本地化Resolver
initLocaleResolver(context);
//初始化主题Resolver
initThemeResolver(context);
//初始化一些个与处理的HandlerMappings
initHandlerMappings(context);
//
initHandlerAdapters(context);
//初始化异常处理的handler
initHandlerExceptionResolvers(context);
//初始化请求路径转换为ViewName 的Translator
initRequestToViewNameTranslator(context);
//初始化ViewResolvers 这个就是针对视图处理的Resolvers 比如jsp处理Resolvers 或者freemarker处理Resolvers
initViewResolvers(context);
//初始化 主要管理flashmap,比如RedirectAttributes 的属性会放到这个里面,默认使用的是SessionFlashMapManager
initFlashMapManager(context);
}
1.2 初始化流程图
1.2.1 HttpServletBean源码解析
HttpServletBean
本身来说是一个普通的servlet而已,主要做一些资源的初始化
public abstract class HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware {
protected final Log logger = LogFactory.getLog(getClass());
/**
* Set of required properties (Strings) that must be supplied as
* config parameters to this servlet.
*/
private final Set<String> requiredProperties = new HashSet<String>();
private ConfigurableEnvironment environment;
/**
* Subclasses can invoke this method to specify that this property
* (which must match a JavaBean property they expose) is mandatory,
* and must be supplied as a config parameter. This should be called
* from the constructor of a subclass.
* <p>This method is only relevant in case of traditional initialization
* driven by a ServletConfig instance.
* @param property name of the required property
*/
protected final void addRequiredProperty(String property) {
this.requiredProperties.add(property);
}
/**
* Map config parameters onto bean properties of this servlet, and
* invoke subclass initialization.
* @throws ServletException if bean properties are invalid (or required
* properties are missing), or if subclass initialization fails.
*/
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
//使用Servlet配置的初始化参数创建一个PropertyValues对象,PropertyValues对象是名值对的集合, 子类也可以指定哪些属性是必须的
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
//把当前的Servlet当作一个Bean, 把Bean的属性以及属性的存取方法信息放入BeanWrapper对象
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//注册一个可以在资源和路径之间进行转化的客户化编辑器,这些资源是这个Web应用的内部资源,例如,一个文件,一个图片等等
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//提供给子类机会增加更多的客户化的编辑器,或者对BeanWrapper进行更多的初始化
initBeanWrapper(bw);
//把初始化制定的参数值赋值到Servlet的属性中,第二个参数true表明忽略位置属性
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
//提供给子类的的初始化方法 目前是FrameworkServlet 进行了实现
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}