该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读
Spring 版本:5.2.4.RELEASE
该系列其他文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》
LocaleResolver 组件LocaleResolver 组件,本地化(国际化)解析器,提供国际化支持
回顾先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 LocaleResolver 组件,可以回到《一个请求的旅行过程》中的 DispatcherServlet 的 processDispatchResult 方法中看看,如下:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { // ... 省略相关代码 // <3> 是否进行页面渲染 if (mv != null && !mv.wasCleared()) { // <3.1> 渲染页面 render(mv, request, response); // <3.2> 清理请求中的错误消息属性 // 因为上述的情况二中 processHandlerException 会通过 WebUtils 设置错误消息属性,所以这里得清理一下 if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } // ... 省略相关代码 } protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. // <1> 解析 request 中获得 Locale 对象,并设置到 response 中 Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); // ... 省略相关代码 // 获得 View 对象 View view; String viewName = mv.getViewName(); // ... 省略相关代码 view = mv.getView(); // ... 省略相关代码 try { // <3> 设置响应的状态码 if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } // <4> 渲染页面 view.render(mv.getModelInternal(), request, response); } // ... 省略相关代码 }在执行完handler处理器后,需要对返回的 ModelAndView 对象进行处理,可能需要调用 render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) 方法,渲染页面
可以看到需要先通过 LocaleResolver 从请求中解析出 java.util.Locale 对象
LocaleResolver 接口org.springframework.web.servlet.LocaleResolver,本地化(国际化)解析器,提供国际化支持,代码如下:
public interface LocaleResolver { /** * 从请求中,解析出要使用的语言。例如,请求头的 "Accept-Language" */ Locale resolveLocale(HttpServletRequest request); /** * 设置请求所使用的语言 */ void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale); }LocaleResolver 接口体系的结构如下:
初始化过程在 DispatcherServlet 的 initLocaleResolver(ApplicationContext context) 方法,初始化 LocaleResolver 组件,方法如下:
private void initLocaleResolver(ApplicationContext context) { try { // 从上下文中获取Bean名称为'localeResolver'的对象 this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); if (logger.isTraceEnabled()) { logger.trace("Detected " + this.localeResolver); } else if (logger.isDebugEnabled()) { logger.debug("Detected " + this.localeResolver.getClass().getSimpleName()); } } catch (NoSuchBeanDefinitionException ex) { // We need to use the default. /** * 从配置文件中获取默认的 {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver} */ this.localeResolver = getDefaultStrategy(context, LocaleResolver.class); if (logger.isTraceEnabled()) { logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME + "': using default [" + this.localeResolver.getClass().getSimpleName() + "]"); } } }
获得 Bean 名称为 "localeResolver",类型为 LocaleResolver 的 Bean ,将其设置为 localeResolver
如果未获得到,则获得默认配置的 LocaleResolver 实现类,调用 getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) 方法,就是从 DispatcherServlet.properties 文件中读取 LocaleResolver 的默认实现类,如下:
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver我看了一下,Spring Boot 没有提供其他的实现类,默认也是这个
AcceptHeaderLocaleResolverorg.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver,实现 LocaleResolver 接口,通过检验 HTTP 请求的Accept-Language头部来解析区域,默认的实现类
构造方法 public class AcceptHeaderLocaleResolver implements LocaleResolver { private final List<Locale> supportedLocales = new ArrayList<>(4); @Nullable private Locale defaultLocale; }上面两个属性默认都没有设置值
resolveLocale