DispatcherServelt本质是也是Servlet,由Servlet容器进行加载。
1.Servlet接口提供了Servlet的初始化方法:init(ServletConfig config)。
2.GenericServlet实现了方法init(ServletConfig config),此方法调用具体的初始化方法:init()。
3.HttpServletBean重写了方法init(),并用修饰符final将方法变成了不可重写,此处可以用模板方法来理解:初始化的逻辑过程在此方法中定义好了,具体的实现由子类来完成。
@Override
public final void init() throws ServletException {
// Set bean properties from init parameters.
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);
}
}
// Let subclasses do whatever initialization they like.
// 由子类FrameworkServlet来完成
initServletBean();
}
4.FrameworkServlet重写了initServletBean(),并用修饰符final将方法变成了不可重写,此处也可以用模板方法来理解,
初始化的逻辑过程在此方法中定义好了,具体的实现由子类来完成。
@Override
protected final void initServletBean() throws ServletException {
try {
// 调用initWebApplicationContext()方法,完成初始化
this.webApplicationContext = initWebApplicationContext();
// 方法体为空,子类可以重写实现扩展
initFrameworkServlet();
}
}
5.FrameworkServlet.initWebApplicationContext中调用的方法onRefresh(ApplicationContext context)的方法体也为空,由子类DispatcherServlet负责实现。
6.DispatcherServlet重写了方法onRefresh,此方法调用具体的初始化过程initStrategies(ApplicationContext context)
/** * This implementation calls {@link #initStrategies}. */
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
7.DispatcherServlet的核心初始化过程是由下面的方法负责完成的。
protected void initStrategies(ApplicationContext context) {
// Spring MVC扩展点,核心的配置文件,也就是默认核心组件在DispatcherServlet.properties中
// 1. 文件上传解析类,配置文件中没有默认配置.
// 要想实现文件上传的功能,需要我们在xml配置文件中配置名multipartResolver名为multipartResolver的bean
// 下面一行被注释的代码告诉我们,没有配置则不具备此功能
// this.multipartResolver = null;
// 此解析类需要实现接口MultipartResolver
// 可以配置此类org.springframework.web.multipart.support.StandardServletMultipartResolver,作为文件上传的解析类
// 当然也可以在xml文件中配置定制化的实现MultipartResolver接口的文件上传解析类
initMultipartResolver(context);
// 2.国际化
initLocaleResolver(context);
// 3.主题解析
initThemeResolver(context);
// 4.请求到处理器的映射
initHandlerMappings(context);
// 5.根据Handler的类型定义不同的处理规则
initHandlerAdapters(context);
// 6.Handler异常处理
initHandlerExceptionResolvers(context);
// 7.view->jsp,默认DefaultRequestToViewNameTranslator(JSP视图)
initRequestToViewNameTranslator(context);
// 8.视图解析:View视图解析成页面,可以设置多个解析策略,默认:InternalResourceViewResolver(JSP)
initViewResolvers(context);
// 9.重定向属性存储集合管理器
initFlashMapManager(context);
}
8.上面的代码中只解释了文件上传组件,其他的组件的具体功能在后面的博文会有具体的描述。下面再解析一下默认组件的加载工程,在相应组件的初始化方法中,如果能在检测到对应的bean组件实例,则直接使用;不能检测到,则通过反射去创建默认配置文件中配置的默认组件。
DispatcherServlet类加载的时候,会在静态代码块中解析默认配置文件。
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);
// 将默认配置解析到集合Properties中
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
通过反射加载配置的默认组件。
@SuppressWarnings("unchecked")
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
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 {
// 反射方式ClassForName(className)加载Class对象
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(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<>();
}
DispatcherServlet的初始化方法,给我们提供了众多的扩展点,让我们可以灵活地定制DispatcherServlet服务(只需要实现其对应的接口并在xml中进行配置),去深入地把控和扩展DispatcherServlet处理Request请求的每一个步骤。