概述
DispatcherServlet#initHandlerAdapters方法用于准备DispatcherServlet处理请求时所使用的HandlerAdapter对象(可以有多个)。这些HandlerAdapter对象获取之后记录在DispatcherServlet的实例成员属性handlerAdapters中。
DispatcherServlet另有一个实例成员属性detectAllHandlerAdapters,该属性缺省为true。
DispatcherServlet准备HandlerAdapter的流程如下 :
-
从容器获取
HandlerAdapter对象;- 当
detectAllHandlerAdapters为true时,从容器(以及祖先容器)获取所有类型为HandlerAdapter的bean组件,记录到handlerAdapters并排序; - 当
detectAllHandlerAdapters为false时,从容器(以及祖先容器)获取名称为handlerAdapter的bean组件,记录到handlerAdapters,这种情况下handlerAdapters中最多有一个元素;
- 当
-
如果上面步骤结束时
handlerAdapters为空则创建缺省HandlerAdapter对象记录到handlerAdapters;
经过上面的流程,我们可以看出:
DispatcherServlet的属性handlerAdapters中总是会有至少一个可供使用的HandlerAdapter对象。- 如果想定制
DispatcherServlet所使用的HandlerAdapter,开发人员可以注册相应的HandlerAdapter对象到容器; - 如果想指定
DispatcherServlet为某一个HandlerAdapter,开发人员可以注册自定义的HandlerAdapter到容器,但必须使用名称handlerAdapter,并且需要先设置DispatcherServlet的属性detectAllHandlerAdapters为false。
到这里,你可能会有疑问,缺省情况下,开发人员并没有往容器中定义
HandlerAdapter组件,但实际上DispatcherServlet能够从容器获得HandlerAdapter组件,这又是为什么呢?关于这一点,请参考 :
源代码解析
本文所用源代码基于
Spring Web MVC 5.1.4.RELEASE
方法 #initHandlerAdapters
/**
* Initialize the HandlerAdapters used by this class.
* If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
* we default to SimpleControllerHandlerAdapter.
*/
private void initHandlerAdapters(ApplicationContext context) {
// 初始化记录 handlerAdapters 对象的属性变量为null
this.handlerAdapters = null;
// 根据属性 detectAllHandlerAdapters 决定是检测所有的 HandlerAdapter 对象,还是
// 使用指定名称的 HandlerAdapter 对象
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
// 从容器及其祖先容器查找所有类型为 HandlerAdapter 的 HandlerAdapter 对象,记录到 handlerAdapters 并排序
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
// 排序,关于这里的排序,可以参考 WebMvcConfigurationSupport 类中对各种 HandlerAdapter bean
// 进行定义时所使用的 order 属性,顺序属性很关键,因为它涉及到 HandlerAdapter 使用时的优先级
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
// 获取名称为 handlerAdapter 的 HandlerAdapter bean 并记录到 handlerAdapters
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
// 如果上面步骤从容器获取 HandlerAdapter 失败,则使用缺省策略创建 HandlerAdapter 对象记录到
// handlerAdapters
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
方法 #getDefaultStrategies
该方法使用指定的策略接口 strategyInterface 创建一组策略对象。上面的方法initHandlerAdapters就是使用该方法创建了一组缺省的HandlerAdapter策略对象。
该方法会使用DispatcherServlet缺省配置文件DispatcherServlet.properties获取缺省要使用的策略实现类。
/**
* Create a List of default strategy objects for the given strategy interface.
* The default implementation uses the "DispatcherServlet.properties" file (in the same
* package as the DispatcherServlet class) to determine the class names. It instantiates
* the strategy objects through the context's BeanFactory.
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
*/
@SuppressWarnings("unchecked")
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// 策略接口长名称作为 key
String key = strategyInterface.getName();
// 这里 defaultStrategies 是一个类静态属性,指向classpath resource 文件 DispatcherServlet.properties
// 该行获取策略接口对应的实现类,是','分割的实现类的长名称
String value = defaultStrategies.getProperty(key);
if (value != null) {
//
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(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) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
}
else {
return new LinkedList<>();
}
}
方法 #createDefaultStrategy
该方法使用AutowireCapableBeanFactory#createBean创建策略实现类的一个实例对象。
/**
* Create a default strategy.
* The default implementation uses
* org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean.
* @param context the current WebApplicationContext
* @param clazz the strategy implementation class to instantiate
* @return the fully configured strategy instance
* @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean
*/
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
文件DispatcherServlet.properties
文件DispatcherServlet.properties是一个属性文件。每个属性的key是一个策略接口的长名称,而value是key指定的策略接口的多个实现类的长名称,每个类名称之间使用,分割。
该文件位于包org.springframework.web.servlet,和DispatcherServlet在同一个pacakge路径下面。具体内容如下 :
# 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.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
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
本文深入解析了DispatcherServlet的initHandlerAdapters方法,该方法负责初始化处理请求时所需的多个HandlerAdapter对象。文章详细介绍了如何根据detectAllHandlerAdapters属性的设置,从容器中获取或创建HandlerAdapter对象,并解释了其排序和默认创建过程。
794

被折叠的 条评论
为什么被折叠?



