spring-boot-2.0.3源码篇 - 国际化
前言
针对spring boot,网上已有很多优质的系列教程,我就不再班门弄斧了(实际上是担心没别人写的好,哈哈哈!)。但是还是想蹭蹭spring boot的热度,即使不考虑微服务,spring boot还是有很多可取优点的,比如自动化配置、系列Starters简化maven的依赖管理等。本系列主要是将工作中涉及到的一些功能利用spring boot整合到一起(工作中还没用到spring-boot)。
maven-ssm-web中的内容会陆续集成进来,最近几篇博客会先介绍一些maven-ssm-web中没有的新内容(因为比较熟嘛!);maven-ssm-web最近会停更,如果有朋友仍需要,还是会继续更新的;spring boot的集成工程是:spring-boot-integrate,系列工程则是: spring-boot-2.0.3。
该系列工程都是基于spring-boot-2.0.3;本文是第一篇,先来点简单的,讲讲spring boot中的国际化,工程地址:spring-boot-i18n
基本版
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com .lee</groupId>
<artifactId>spring-boot-i18n</artifactId>
<version>1.0-SNAPSHOT</version> <properties>
<java.version>1.8</java.version>
</properties> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8880
spring:
#国际化配置
messages:
encoding: utf-8
basename: i18n/messages
#thymeleaf配置
thymeleaf:
cache: false
I18nConfig.java
package com.lee.i18n.config; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; @Configuration
public class I18nConfig { // 配置cookie语言解析器
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver resolver = new CookieLocaleResolver();
resolver.setCookieMaxAge(3600); // cookie有效时长,单位秒
resolver.setCookieName("Language"); //设置存储的Cookie的name为Language
return resolver;
} // 配置一个拦截器,拦截国际化语言的变化
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
//拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor()).addPathPatterns("/**");
}
};
}
}
LoginController.java
package com.lee.i18n.controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class LoginController { @RequestMapping("/login")
public String login() {
return "login";
} @RequestMapping("/index")
public String index() {
return "index";
}
}
messages.properties
index.welcome=欢迎 login.username=登录名
login.password=密码
login.login=登录
messages_en_US.properties
index.welcome=welcome login.username=username
login.password=password
login.login=login
messages_zh_CN.properties
index.welcome=欢迎 login.username=登录名
login.password=密码
login.login=登录
当如上文件配置好之后(其他的可以去spring-boot-i18n拉取),都配置好后,工程跑起来,我们来看看结果,是否达到国际化效果呢? 答案是肯定的嘛!
高级版
基本版有一个缺点,就是国际化资源都写在了一个文件中:messages*.properties,内容都写在一个文件中有一个致命的缺点:文件越大,越难以维护;
那么高级版高级在哪了? 你想的没错,就是将资源按某种性质或者功能划分成资源文件夹,再在资源文件夹下放具体的资源文件,如下图
改动的内容已标明,具体改动的内容可以去spring-boot-i18n拉取;工程跑起来,我们看看结果
源码探究
从两个容器的初始化来看整个过程,是哪两个容器了,一个是spring根容器、一个是spring mvc容器,spring根容器也就是根上下文:WebApplicationContext,spring mvc容器即是:DispatcherServlet;
spring根容器初始化
我们从main函数入手,如下图
initMessageSource():初始化国际化资源,finishBeanFactoryInitialization(beanFactory) 实例化非延迟初始化的bean;spring容器初始化的内容还是非常多的,有兴趣的朋友可以跟着断点调试详细看看初始化话过程; 最终全部bean定义都放在了DefaultListableBeanFactory的beanDefinitionMap中了,后续则从beanDefinitionMap中获取bean定义进行实例化。
spring mvc容器初始化
我们都知道spring mvc的核心类就是DispatcherServlet,我们就从他入手,如下图:
从DispatcherServlet继承关系可知,HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,我们可以以此为入口来追踪DispatcherServlet的初始化过程;DispatcherServlet中的initStrategies方法比较重要,而其中initLocaleResolver(context)和initHandlerMappings(context)和本文的国际化有直接关系,initLocaleResolver(context)将我们自己定义的localeResolver绑到了DispatcherServlet的属性localeResolver中;而initHandlerMappings(context)又将我们自己新增的拦截器LocaleChangeInterceptor添加到了DispatcherServlet的handlerMappings中;
是不是有种很美妙的预感,我们自定义的一些bean都关联到了DispatcherServlet中,而我们的请求url又必须经过DispatcherServlet,这是不是巧合? 很显然这不是!如果你还是一头雾水,对不起! 我们接着往下看......
请求过程
从DispatcherServlet的继承关系可知,请求会经过DispatcherServlet的doService方法,doService会将DispatcherServlet中的localeResolver(也就是我们定义的CookieLocaleResolver对象)绑定到当前request对象中,然后再调用doDispatch进行请求的转发;
LocaleChangeInterceptor的类继承图
可知它继承了HandlerInterceptor,并重写了preHandle,我们就从LocaleChangeInterceptor的preHandle方法开始(请求肯定会经过此方法)阅读源码,打断点追踪,如下如
既然能通过locale参数感知语言的变化,那么肯定也能根据语言加载对应的资源,从而实现国际化(具体如何加载的需要大家自己去阅读源码了!)
源码阅读就此告一段落,不是特别细,只是提供了一个主体流程;强烈建议大家阅读源码的时候,进行断点调试跟踪,不容易跟丢!
参考
第三章 DispatcherServlet详解 ——跟开涛学SpringMVC
spring-boot-2.0.3源码篇 - 国际化的更多相关文章
- Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...
- springboot2.0.3源码篇 - 自动配置的实现,发现也不是那么复杂
前言 开心一刻 女儿: “妈妈,你这么漂亮,当年怎么嫁给了爸爸呢?” 妈妈: “当年你爸不是穷嘛!‘ 女儿: “穷你还嫁给他!” 妈妈: “那时候刚刚毕业参加工作,领导对我说,他是我的扶贫对象,我年轻 ...
- Spring Boot 揭秘与实战 源码分析 - 工作原理剖析
文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...
- Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机
文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...
- Spring Boot 注解之ObjectProvider源码追踪
最近依旧在学习阅读Spring Boot的源代码,在此过程中涉及到很多在日常项目中比较少见的功能特性,对此深入研究一下,也挺有意思,这也是阅读源码的魅力之一.这里写成文章,分享给大家. 自动配置中的O ...
- spring-boot-2.0.3源码篇 - pageHelper分页,绝对有值得你看的地方
前言 开心一刻 说实话,作为一个宅男,每次被淘宝上的雄性店主追着喊亲,亲,亲,这感觉真是恶心透顶,好像被强吻一样.........更烦的是我每次为了省钱,还得用个女号,跟那些店主说:“哥哥包邮嘛么叽. ...
- spring-boot-2.0.3源码篇 - filter的注册,值得一看
前言 开心一刻 过年女婿来岳父家走亲戚,当时小舅子主就问:姐夫,你什么时候能给我姐幸福,让我姐好好享受生活的美好.你们这辈子不准备买一套大点的房子吗?姐夫说:现在没钱啊!不过我有一个美丽可爱的女儿,等 ...
- SpringBoot 源码解析 (八)----- Spring Boot 精髓:事务源码解析
本篇来讲一下SpringBoot是怎么自动开启事务的,我们先来回顾一下以前SSM中是如何使用事务的 SSM使用事务 导入JDBC依赖包 众所周知,凡是需要跟数据库打交道的,基本上都要添加jdbc的依赖 ...
- spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
前言 开心一刻 一名劫匪慌忙中窜上了一辆车的后座,上车后发现主驾和副驾的一男一女疑惑地回头看着他,他立即拔出枪威胁到:“赶快开车,甩掉后面的警车,否则老子一枪崩了你!”,于是副驾上的男人转过脸对那女的 ...
随机推荐
- [字符串][NOIP2012]Vigenère密码
Vigenère密码 题目描述 16世纪法国外交家Blaise de Vigenère设计了一种多表密码加密算法——Vigenère密码.Vigenère密码的加密解密算法简单易用,且破译难度比较高, ...
- JPanel JScrollPanel
JPanel 和 JScrollPanel 都属于面板,也是 Swing 中间容器,可以作为容器存放组件,但必须被添加到其他容器中. JPanel 可以聚集一些组件来布局, JScrollPanel ...
- hibernate的Could not execute JDBC batch update错误原因及处理
http://blog.csdn.net/derpvailzhangfan/article/details/2332795\ 上述问题: 一设置关联 二包含关键字 三 映射文件设置 catalog=“ ...
- nigx
1.反向代理 2.负载均衡(weight:设置权重) 3.高可用(场景:当主服务器死掉后 拥有备用服务器承接后续的访问) 安装 Keepalived实现
- qhfl-4 注册-登录-认证
认证 任何的项目都需要认证,当用户输入了用户名和密码,验证通过,代表用户登录成功 那HTTP请求是无状态的,下次这个用户再请求,是不可能识别这个用户是否登录的 就要有自己的方式来实现这个认证,用户登录 ...
- EF6学习笔记(六) 创建复杂的数据模型
EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇原文地址:Creating a More Complex Data Model 本篇讲的比较碎,很多内容本人 ...
- 【leetcode】 算法题3 无重复字符的最长子串
问题 给定一个字符串,找出不含有重复字符的最长子串的长度. 示例: 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度 ...
- 拷问传统企业CIO:微服务化值得吗?
所谓数字化转型升级,就是以数字技术优化传统资源,企业需要谨慎地选择合适的技术逐步完成自己的数字化战略.以推出轻舟微服务平台的网易云为代表,云计算公司正在微服务领域发力,促进企业数字化创新.那么,微服务 ...
- Codeforces Round #525 (Div. 2) E. Ehab and a component choosing problem 数学
题意:给出树 求最大的sigma(a)/k k是选取的联通快个数 联通快不相交 思路: 这题和1个序列求最大的连续a 的平均值 这里先要满足最大平均值 而首先要满足最大 也就是一个数的时候可 ...
- HTML各个版本以及对应doctype
HTML发布的正式历史版本: 1.HTML2.0 2.HTML3.2 3.HTML4.0 4.HTML4.01 5.XHTML1.0 6.XHTML1.1 7.XHTML2.0 中途放弃,未完成 8 ...