博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java框架-Spring MVC理解005-DispatcherServlet
阅读量:5311 次
发布时间:2019-06-14

本文共 7124 字,大约阅读时间需要 23 分钟。

DispatcherServlet

  通过源码我们可以看到,onRefresh方法是DispatcherServlet的入口方法。onRefresh中简单地调用了initStrategies,在initStrategies中调用了9个初始化方法。

 

// org.springframework.web.servlet.DispatcherServletprotected 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);}

 

我们会想:为什么不将initStrategies的具体实现直接写到onRefresh中呢?initStrategies方法不是多余的吗?

  其实这主要是分层的原因,onRefresh是用来刷新容器的,initStrategies用来初始化一些策略组件。如果把initStrategies里面的代码直接写到onRefresh里面,对于程序的运行也没有影响,不过这样一来,如果在onRefresh中想再添加别的功能,就会没有将其单独写一个方法出来逻辑清晰,不过这并不是最重要的,更重要的是,如果在别的地方也需要调用initStrategies方法(如需要修改一些策略后进行热部署),但initStrategies没独立出来,就只能调用onRefresh,那样在onRefresh增加了新功能的时候就麻烦了。另外单独将initStrategies写出来还可以被子类覆盖,使用新的模式进行初始化。

  initStrategies的具体内容非常简单,就是初始化的9个组件,下面以LocaleResolver为例来分析具体的初始化方式://初始化区域解析器

// org.springframework.web.servlet.DispatcherServletprivate void initLocaleResolver(ApplicationContext context) {    try {        // 在context中获取        this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);        if (logger.isDebugEnabled()) {            logger.debug("Using LocaleResolver [" + this.localeResolver + "]");        }    }catch (NoSuchBeanDefinitionException ex) {        // 使用默认策略        this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);        if (logger.isDebugEnabled()) {            logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +            "': using default [" + this.localeResolver + "]");        }    }}

初始化方式分两步:首先通过context.getBean在容器里面按注册时的名称或类型(这里指“localeResolver”名称或者LocaleResolver.class类型)进行查找,所以在Spring MVC的配置文件中只需要配置相应类型的组件,容器就可以自动找到。如果找不到就调用getDefaultStrategy按照类型获取默认的组件。需要注意的是,这里的context指的是Frame-workServlet中创建的WebApplicationContext,而不是ServletContext。下面介绍getDefault-Strategy是怎样获取默认组件的。

// org.springframework.web.servlet.DispatcherServletprotected
T getDefaultStrategy(ApplicationContext context, Class
strategyInterface) { List
strategies = getDefaultStrategies(context, strategyInterface); if (strategies.size() != 1) { throw new BeanInitializationException( "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]"); } return strategies.get(0);}protected
List
getDefaultStrategies(ApplicationContext context, Class
strategyInterface) { String key = strategyInterface.getName(); //从defaultStrategies获取所需策略的类型 String value = defaultStrategies.getProperty(key); if (value != null) { //如果有多个默认值,以逗号分割为数组 String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List
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( "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
(); }}

  可以看到getDefaultStrategy中调用了getDefaultStrategies,后者返回的是List,这是因为HandlerMapping等组件可以有多个,所以定义了getDefaultStrategies方法,getDefaultStrategy直接调用了getDefaultStrategies方法,并返回返回值的第一个结果。getDefaultStrategies中实际执行创建的方法是ClassUtils.forName,它需要的参数是class-Name,所以最重要的是看className怎么来的,找到了className的来源,也就可以理解默认初始化的方式。className来自classNames,classNames又来自value,而value来自default-Strategies.getProperty(key)。所以关键点就在defaultStrategies中,defaultStrategies是一个静态属性,在static块中进行初始化的。

// org.springframework.web.servlet.DispatcherServletprivate 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 'DispatcherServlet.properties': " + ex.getMessage());    }}
# org.springframework.web.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.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

  我们看到defaultStrategies是DispatcherServlet类所在包下的DEFAULT_STRATEGIES_PATH文件里定义的属性,DEFAULT_STRATEGIES_PATH的值是DispatcherServlet.properties。所以defaultStrategies里面存放的是org.springframework.web.DispatcherServlet.properties里面定义的键值对,代码如上。

  可以看到,这里确实定义了不同组件的类型,一共定义了8个组件,处理上传组件Multi-partResolver是没有默认配置的,这也很容易理解,并不是每个应用都需要上传功能,即使需要上传也不一定就要使用MultipartResolver,所以MultipartResolver不需要默认配置。另外HandlerMapping、HandlerAdapter和HandlerExceptionResolver都配置了多个,其实View-Resolver也可以有多个,只是默认的配置只有一个。

  这里需要注意两个问题:首先默认配置并不是最优配置,也不是spring的推荐配置,只是在没有配置的时候可以有个默认值,不至于空着。里面的有些默认配置甚至已经被标注为@Deprecated,表示已弃用,如DefaultAnnotationHandlerMapping、Annotation-MethodHandlerSolver不需要默认配置。另外HandlerMapping、andlerAdapter和HandlerExceptionResolver都配置了多个,其实View-Resolver也可以有多个,只是默认的配置只有一个。

DispatcherServlet的创建过程主要是对9大组件进行初始化,具体每个组件的作用后面具体讲解。

 

转载于:https://www.cnblogs.com/yulibo/p/9069449.html

你可能感兴趣的文章
面试题2
查看>>
selenium+java iframe定位
查看>>
P2P综述
查看>>
第五章 如何使用Burp Target
查看>>
Sprint阶段测试评分总结
查看>>
sqlite3经常使用命令&语法
查看>>
linux下编译openjdk8
查看>>
【python】--迭代器生成器装饰器
查看>>
Pow(x, n)
查看>>
安卓当中的线程和每秒刷一次
查看>>
每日一库:Modernizr.js,es5-shim.js,es5-safe.js
查看>>
ajax连接服务器框架
查看>>
wpf样式绑定 行为绑定 事件关联 路由事件实例
查看>>
利用maven管理项目之POM文件配置
查看>>
TCL:表格(xls)中写入数据
查看>>
Oracle事务
查看>>
String类中的equals方法总结(转载)
查看>>
属性动画
查看>>
标识符
查看>>
给大家分享一张CSS选择器优选级图谱 !
查看>>