1.核心接口
dispatchServlet UML图:
DispatchServlet,httpservletBean,FrameWorkServlet这三个类直接实现了EnvironmentCapable,EnvironmentAware以及ApplicationContextAware接口.
科普:
①:XXXAwaare在spring里表示对XXX感知,也就是:如果在某个类里面想要使用spring的一些东西,就可以通过实现XXXAware接口告诉spring,spring看到后就会给你送过来,而接收的方式是通过实现接口唯一的方法setXXX().比如:有个类想要使用当前的applicationContext,我们只需要让他实现ApplicationContextAware接口,然后实现接口中唯一的方法,void setApplicationContext(ApplicationContext applicaitonContext)就可以了,spring会自动调用这个方法将applicationContext传过来.
②:XXXCapable在spring中就是具有XXX的能力,比如:EnvironmentCapable就是告诉spring,他有提供Environment的能力,EnvironmentCapable唯一的方法及时Environment getEnvironment()当;spring需要Environment时,就会调用其get方法跟他要.
springmvc启动
httpServletBean
DispatchServlet创建时,可以直接调用无参的init方法,dispatchServlet默认调用httpServletbean的init方法,如下:(篇幅有点长,省略try…catch)
public final void init() throws ServletException {
//将servlet中配置的参数封装到pvs中,requireProperties为必须参数,没有将抛出ServletException
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
//模板方法,可以在子类中调用,做一些初始化工作(默认空实现).这里的bw代表Dispatchservlet;
this.initBeanWrapper(bw);
//通过beanWrapper将配置的初始化值(如:contextConfigLocation属性)设置到dispatchServlet中;
bw.setPropertyValues(pvs, true);
//模板方法,子类初始化的方法入口.这里做个空实现,具体实现在FrameWorkServlet中.
this.initServletBean();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
}
}
FrameWorkServlet
从httpServletBean中可知,FrameworkServlet的初始化入口方法是initservletBean().方法代码如下:
//去除try..catch以及日志打印代码,其核心只做了两件事情
protected final void initServletBean() throws ServletException {
// 1.初始化WebApplcationContext(ConfigurableWebApplicationContext)
this.webApplicationContext = this.initWebApplicationContext();
// 2.初始化FrameworkServlet,次方式为模板方法,空实现,子类Dispatchservlet并没有使用它
this.initFrameworkServlet();
}
可见frameworkservlet在构建过程中的主要作用就是初始化WebApplicationContext,下面为initWebApplicationContext代码:
protected WebApplicationContext initWebApplicationContext() {
//获取rootContext
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
//如果已经通过构造方法设置了WebApplicationContext
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) {
//当webApplicationContext已经存在于servletContext中,通过配置在servlet中的contextAttribute获取
wac = this.findWebApplicationContext();
}
if (wac == null) {
//如果webApplicationContext还没有,则创建一个,一般情况都是调用 这个创建.
wac = this.createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
//模板方法,当ContextRefreshedEvent事件没有触发时调用此方法,在子类dispatchServlet中具体实现.
this.onRefresh(wac);
}
if (this.publishContext) {
//将ApplicationContext设置到servletContext中,
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
}
return wac;
}
主要分析一下createWebApplicationContext(rootContext) 方法,贴代码:
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
//获取创建类型
Class<?> contextClass = this.getContextClass();
//检查创建类型( A.class.isAssignableFrom(B.class):判断A是不是B的超类) contextclass 默认为XmlWebApplicationContext
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);
//将设置的contextConfigLocaltion传递给wac
wac.setConfigLocation(this.getContextConfigLocation());
//这里面添加了应用 监听器,ContextRefreshListener
this.configureAndRefreshWebApplicationContext(wac);
return wac;
}
}
ContextRefreshListener是FrameWorkServlet的内部类
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
//模板方法,在子类dispatchservlet中具体实现
onRefresh(event.getApplicationContext());
}
DispatchServlet
onRefresh 方法是Dispatchservlet的入口方法,onrefresh中调用了initStrategies,在initstrategies中调用了9个方法.
//org.springframework.web.servlet.DispatcherServlet
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
//熟悉的味道
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
这里9个初始化方法都类似,这里以初始化handlerMapping 为例,
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//首先在applicationContext中获取
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,则使用默认策略
if (this.handlerMappings == null) {
//加载默认策略
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
下面介绍一下getDefaultStrategies 这个方法,贴代码:
从这段代码可以看出:默认策略返回的是个集合,集合如果不为空,则直接返回了集合中的第一个策略配置.
//strategyInterface 为HandlerMapping.class
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
//从defaultStrategies中获取该策略的值
String value = defaultStrategies.getProperty(key);
if (value != null) {
//多个值之间用逗号分隔
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
// ... 省略
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}
defaultStrategies ? springmvc都有哪些默认的策略配置?
继续贴代码,springmvc从默认的DispatcherServlet.properties文件中加载默认策略
//org.springframework.web.servlet.DispatcherServlet
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final Properties defaultStrategies;
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
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
springmvc创建完成!
后续更新springmvc怎样处理请求
FrameworkServlet中的模板方法doService在其子类中Dispatchservlet中的具体实现,以及springmvc,通过request获取hangler,根据handler找到对应的handlerAdapt,用handler处理handler,调用processDispatchResult方法处理上面返回的结果(包含找到view并输出渲染给用户),并展示给用户.