1.目前自己在做一个项目用到了 Spring MVC 第一次用所以记录一下百度百科对DispatcherServlet的解释DispatcherServlet 是前置控制.配置在web.xml文件中的.拦截匹配的请求.DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据响应的规则分发到目标Controller来处理,是配置spring MVC的第一步。简单说就是继承了HttpServlet类,他也是Spring MVC的总控器
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml-->
<!-- <init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value> 默认
</init-param> -->
<!-- 设置编码格式 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
查看DispatcherServlet源代码 可以发现他继承extends FrameworkServlet
他们的继承关系大概如下
DispatcherServlet extends abstract class FrameworkServlet extends abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware
可能不是很明白.那我就一步一步来
DispatcherServlet.Java
public class DispatcherServlet extends FrameworkServlet {
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final Properties defaultStrategies;
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
}
查看DispatcherServlet源码可以发现 启动时候他会首先加载这个properties文件
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
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
从这个properties文件看到他会加载怎么多的spring bean
一个个来说吧
1.AcceptHeaderLocaleResolver(简单说就是国际化类)
根据浏览器Http Header中的accept-language域判定(accept-language域中一般包含了当前操作系统的语言设定,可通过 HttpServletRequest.getLocale方法获得此域的内容)。 改变Local 是不支持的,即不能调用LocaleResolver接口的 setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale); 方法设置Local.
2.FixedThemeResolver(这快我也不理解.希望有高手可以给我解答下.顺便举个列子)
主题解析器 //初始化themeResolver bean, 默认实现FixedThemeResolver.
我的理解就是主要处理界面的样式比如 CSS 等之类的.
3.BeanNameUrlHandlerMapping,DefaultAnnotationHandlerMapping
初始化handlerMappings集,将用户请求映射到我们定义的Controller中
(1).BeanNameUrlHandlerMapping默认操作影射机制。通过bean的名影射到客户端请求的url
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
/**
* Checks name and aliases of the given bean for URLs, starting with "/".
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<String>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = getApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
默认情况下,如果spring找不到url影射的话就会自动创建
BeanNameUrlHandlerMapping
(2).DefaultAnnotationHandlerMapping
在Spring3.2.12已经不建议使用此类了.
4.HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter , AnnotationMethodHandlerAdapter
处理请求的映射AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上
下面是HandlerAdapter接口的实现类
HandlerAdapter系统级的接口,它允许在不同的请求处理器和DispatcherServlet间保持低耦合性。只要HandlerAdapter经过配 置,DispatcherServlet就能与任何类型的请求处理器相互作用。
5.HandlerExceptionResolver(异常处理类)
public abstract class FrameworkServlet extends HttpServletBean {
/**
* Suffix for WebApplicationContext namespaces. If a servlet of this class is
* given the name "test" in a context, the namespace used by the servlet will
* resolve to "test-servlet".
*/
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
HttpServletBean.Java
public abstract class HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware {
DispatcherServlet实现了他的父类FrameworkServlet的onRefresh
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
//初始化默认的Spring Web MVC框架使用的策略(
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
简述DispatcherServlet的运行流程:
1.首先会加载初始化配置文件.该配置文件已经在上面贴出了.
(DispatcherServlet.properties 主要包括
LocaleResolver(本地化解析器,AcceptHeaderLocaleResolver)
ThemeResolver(主题解析器,FixedThemeResolver)
HandlerMapping(处理器映射,BeanNameUrlHandlerMapping)
HandlerAdapter(控制适配器,多个)
ViewResolver(视图解析器,InternalResourceViewResolver)
RequestToViewNameTranslator(请求到视图名的翻译器,DefaultRequestToViewNameTranslator)
)
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
2. 因为DispatcherServlet继承了FrameworkServlet 而FrameworkServlet 有继承了HttpServletBean , HttpServletBean 则最终继承了 HttpServlet
而因为HttpServletBean继承了HttpServlet 有重写了int()方法
HttpServletBean.init()源码
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
//数据绑定 动态应用程序的域模型 绑定起来
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//为当前的HttpServletBean初始化BeanWrapper对象, 并有可能包含自定义Editor对象
initBeanWrapper(bw);
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.
//在所有的bean属性被设定后调用, 创建了servlet的WebApplicationContext对象
//在他的子类 FrameworkServlet 重写了 initServletBean
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
FrameworkServlet 的initServletBean源码
/**
* Overridden method of {@link HttpServletBean}, invoked after any bean properties
* have been set. Creates this servlet's WebApplicationContext.
*/
@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 {
//WebApplicationContext继承自ApplicationContext
this.webApplicationContext = initWebApplicationContext();//在此方法里调用了onRefresh
initFrameworkServlet();
}
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");
}
}
FrameworkServlet
.initWebApplicationContext源码
/**
* Initialize and publish the WebApplicationContext for this servlet.
* <p>Delegates to {@link #createWebApplicationContext} for actual creation
* of the context. Can be overridden in subclasses.
* @return the WebApplicationContext instance
* @see #FrameworkServlet(WebApplicationContext)
* @see #setContextClass
* @see #setContextConfigLocation
*/
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
//触发refresh事件, 会调用DispatcherServlet的onRefresh方法
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
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;
}
DispatcherServlet.onRefresh源码
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
DispatcherServlet.
initStrategies源码
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
大概就这样一个流程