系统测试架构
系统测试架构
软件测试描述一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。软件测试的经典定义是:在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。
现代软件开发项目中,分工明确,基本上都会有研发、测试、QA 等角色。不同角色由于关注的视角不同,测试目标和测试方法也不完全相同。本文主要从研发、测试的视角去考量软件测试技术。
注意:
- 为了方便,只有测试人员需要关注的测试点用【测试】标注;
- 而只有研发人员需要关注的测试点用【研发】标注;
- 都需要关注的测试点则不作标注。
测试方法分类
从测试设计方法分类
- 黑盒测试【测试】 - 把软件系统当作一个“黑箱”,无法了解或使用系统的内部结构及知识。从软件的行为,而不是内部结构出发来设计测试。
- 白盒测试【研发】 - 设计者可以看到软件系统的内部结构,并且使用软件的内部知识来指导测试数据及方法的选择。
- 灰盒测试 - 介于黑盒和白盒之间。
小结:
- 黑河测试通常针对的是软件的行为或功能,一般是测试人员主要关注的。
- 白盒测试通常则需要对软件有一定程度的了解,一般是开发人员所关注的。
- 灰盒测试通常是为了测试软件在特定的场景下的表现,而非主场景。
从测试的目的分类
功能测试
- 单元测试(Unit Test) - 在最低粒度的功能/参数上验证程序的准确性,比如测试一个函数的正确性。【研发】
- 常用技术:junit4、junit5、mockito、assertj-core
- 功能测试(Functional Test) - 验证模块的功能。【测试】
- 集成测试(Integration Test) - 验证几个互相有依赖关系的模块的功能。【测试】
- 场景测试(Scenario Test)- 验证几个模块是否能完成一个用户场景。【测试】
- 系统测试(System Test) - 对于整个系统功能的测试。【测试】
- Alpha 测试 - 软件测试人员在真实用户环境中对软件进行全面的测试。【测试】
- Beta 测试 - 也叫公测,是真实的用户在真实的环境中进行的测试。
非功能测试
- 压力测试(Stress test) - 验证软件在超过负载设计的情况下仍能返回正确的结果,没有崩溃
- 负载测试(Load test) - 测试软件在负载情况下能否正常工作
- 性能测试(Performance test) - 测试软件的效能,是否提供满意的服务质量。
- 常用技术:JMeter、JMH。
- 软件辅助功能测试(Accessibility test) - 测试软件是否向残疾用户提供足够的辅助功能
- 本地化/全球化测试(Localization/Globalization)
- 兼容性测试(Compatibility Test)
- 配置测试(Configuration Test) - 测试软件在各种配置下能否正常工作
- 可用性测试(Usability Test) – 测试软件是否好用
- 安全性测试(Security Test)
参考资料
Intellij IDEA 快速入门
Intellij IDEA 快速入门
快捷键
核心快捷键
IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建议了键盘快捷键。在这个主题中,您可以找到最不可缺少的列表,使 IntelliJ IDEA 轻松实现第一步。
核心快捷键表:
操作 | 快捷键 |
---|---|
根据名称查找操作 | Ctrl+Shift+A |
显示可用 意图操作 列表 | Alt+Enter |
切换视图 (Project,Structure, etc.). | Alt+F1 |
切换工具窗口和在编辑器中打开的文件 | Ctrl+Tab |
显示 导航栏. | Alt+Home |
插入代码模板. | Ctrl+J |
在周围插入代码模板. | Ctrl+Alt+J |
Edit an item from the Project or another tree view. | F4 |
注释 | Ctrl+/ Ctrl+Shift+/ |
根据名称查找类或文件. | Ctrl+N Ctrl+Shift+N |
拷贝当前行或指定的行. | Ctrl+D |
增加或减少选中的表达式. | Ctrl+W and Ctrl+Shift+W |
在当前文件查找或替换. | Ctrl+F Ctrl+R |
在项目中或指定的目录中查找或替换 | Ctrl+Shift+F Ctrl+Shift+R |
全局搜索 | 双击 Shift |
快速查看选中对象的引用. | Ctrl+Shift+F7 |
展开或折叠编辑器中的代码块. | Ctrl+NumPad Plus Ctrl+NumPad - |
调用代码完成. | Ctrl+Space |
智能声明完成. | Ctrl+Shift+Enter |
智能补全代码 | Ctrl+Shift+Space |
显示可用的重构方法列表 | Ctrl+Shift+Alt+T |
快捷键分类
Tradition
快捷键 | 介绍 |
---|---|
Ctrl + Z | 撤销 |
Ctrl + Shift + Z | 取消撤销 |
Ctrl + X | 剪切 |
Ctrl + C | 复制 |
Ctrl + S | 保存 |
Tab | 缩进 |
Shift + Tab | 取消缩进 |
Shift + Home/End | 选中光标到当前行头位置/行尾位置 |
Ctrl + Home/End | 跳到文件头/文件尾 |
Editing
快捷键 | 介绍 |
---|---|
Ctrl + Space | 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号(必备) |
Ctrl + Alt + Space | 类名自动完成 |
Ctrl + Shift + Enter | 自动结束代码,行末自动添加分号(必备) |
Ctrl + P | 方法参数提示显示 |
Ctrl + Q | 光标所在的变量/类名/方法名等上面(也可以在提示补充的时候按),显示文档内容 |
Shift + F1 | 如果有外部文档可以连接外部文档 |
Ctrl + F1 | 在光标所在的错误代码处显示错误信息(必备) |
Alt + Insert | 代码自动生成,如生成对象的 set/get 方法,构造函数,toString() 等(必备) |
Ctrl + O | 选择可重写的方法 |
Ctrl + I | 选择可继承的方法 |
Ctrl + Alt + T | 对选中的代码弹出环绕选项弹出层(必备) |
Ctrl + / | 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号(必备) |
Ctrl + Shift + / | 代码块注释(必备) |
Ctrl + W | 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围(必备) |
Ctrl + Shift + W | 递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围(必备) |
Alt + Q | 弹出一个提示,显示当前类的声明/上下文信息 |
Alt + Enter | IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同(必备) |
Ctrl + Alt + L | 格式化代码,可以对当前文件和整个包目录使用(必备) |
Ctrl + Alt + O | 优化导入的类,可以对当前文件和整个包目录使用(必备) |
Ctrl + Alt + I | 光标所在行 或 选中部分进行自动代码缩进,有点类似格式化 |
Ctrl + Shift + C | 复制当前文件磁盘路径到剪贴板(必备) |
Ctrl + Shift + V | 弹出缓存的最近拷贝的内容管理器弹出层 |
Ctrl + Alt + Shift + C | 复制参考信息 |
Ctrl + Alt + Shift + V | 无格式黏贴(必备) |
Ctrl + D | 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面(必备) |
Ctrl + Y | 删除光标所在行 或 删除选中的行(必备) |
Ctrl + Shift + J | 自动将下一行合并到当前行末尾(必备) |
Shift + Enter | 开始新一行。光标所在行下空出一行,光标定位到新行位置(必备) |
Ctrl + Shift + U | 对选中的代码进行大/小写轮流转换(必备) |
Ctrl + Shift + ]/[ | 选中从光标所在位置到它的底部/顶部的中括号位置(必备) |
Ctrl + Delete | 删除光标后面的单词或是中文句(必备) |
Ctrl + BackSpace | 删除光标前面的单词或是中文句(必备) |
Ctrl + +/- | 展开/折叠代码块 |
Ctrl + Shift + +/- | 展开/折叠所有代码(必备) |
Ctrl + F4 | 关闭当前编辑文件 |
Ctrl + Shift + Up/Down | 光标放在方法名上,将方法移动到上一个/下一个方法前面,调整方法排序(必备) |
Alt + Shift + Up/Down | 移动光标所在行向上移动/向下移动(必备) |
Ctrl + Shift + 左键单击 | 把光标放在某个类变量上,按此快捷键可以直接定位到该类中(必备) |
Alt + Shift + 左键双击 | 选择被双击的单词/中文句,按住不放,可以同时选择其他单词/中文句(必备) |
Ctrl + Shift + T | 对当前类生成单元测试类,如果已经存在的单元测试类则可以进行选择(必备) |
Search/Replace
快捷键 | 介绍 |
---|---|
Double Shift | 弹出 Search Everywhere 弹出层 |
F3 | 在查找模式下,定位到下一个匹配处 |
Shift + F3 | 在查找模式下,查找匹配上一个 |
Ctrl + F | 在当前文件进行文本查找(必备) |
Ctrl + R | 在当前文件进行文本替换(必备) |
Ctrl + Shift + F | 根据输入内容查找整个项目 或 指定目录内文件(必备) |
Ctrl + Shift + R | 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件(必备) |
Usage Search
快捷键 | 介绍 |
---|---|
Alt + F7 | 查找光标所在的方法/变量/类被调用的地方 |
Ctrl + Alt + F7 | 显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来 |
Ctrl + Shift + F7 | 高亮显示所有该选中文本,按 Esc 高亮消失(必备) |
Compile and Run
快捷键 | 介绍 |
---|---|
Ctrl + F9 | 执行 Make Project 操作 |
Ctrl + Shift + F9 | 编译选中的文件/包/Module |
Shift + F9 | Debug |
Shift + F10 | Run |
Alt + Shift + F9 | 弹出 Debug 的可选择菜单 |
Alt + Shift + F10 | 弹出 Run 的可选择菜单 |
Debugging
快捷键 | 介绍 |
---|---|
F7 | 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中 |
F8 | 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内 |
Shift + F7 | 在 Debug 模式下,智能步入。断点所在行上有多个方法调用,会弹出进入哪个方法 |
Shift + F8 | 在 Debug 模式下,跳出,表现出来的效果跟 F9 一样 |
Alt + F8 | 在 Debug 模式下,选中对象,弹出可输入计算表达式调试框,查看该输入内容的调试结果 |
Alt + F9 | 在 Debug 模式下,执行到光标处 |
F9 | 在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上 |
Ctrl + F8 | 在 Debug 模式下,设置光标当前行为断点,如果当前已经是断点则去掉断点 |
Ctrl + Shift + F8 | 在 Debug 模式下,指定断点进入条件 |
Navigation
快捷键 | 介绍 |
---|---|
Ctrl + N | 跳转到类(必备) |
Ctrl + Shift + N | 跳转到文件(必备) |
Ctrl + Alt + Shift + N | 跳转到符号(必备) |
Alt + Left/Right | 切换当前已打开的窗口中的子视图,比如 Debug 窗口中有 Output、Debugger 等子视图,用此快捷键就可以在子视图中切换(必备) |
F12 | 回到前一个工具窗口(必备) |
ESC | 从工具窗口进入代码文件窗口(必备) |
Shift + ESC | 隐藏当前 或 最后一个激活的工具窗口 |
Ctrl + G | 跳转到当前文件的指定行处 |
Ctrl + E | 显示最近打开的文件记录列表(必备) |
Ctrl + Shift + E | 显示最近编辑的文件记录列表(必备) |
Ctrl + Alt + Left/Right | 跳转到上一个/下一个操作的地方(必备) |
Ctrl + Shift + Backspace | 退回到上次修改的地方(必备) |
Alt + F1 | 显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择(必备) |
Ctrl + B/Ctrl + 左键单击 | 跳转到声明处 |
Ctrl + Alt + B | 在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口 |
Ctrl + Shift + B | 跳转到类型声明处(必备) |
Ctrl + Shift + I | 快速查看光标所在的方法 或 类的定义 |
Ctrl + U | 前往当前光标所在的方法的父类的方法/接口定义(必备) |
Alt + Up/Down | 跳转到当前文件的前一个/后一个方法(必备) |
Ctrl + ]/[ | 跳转到当前所在代码的花括号结束位置/开始位置 |
Ctrl + F12 | 弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选 |
Ctrl + H | 显示当前类的层次结构 |
Ctrl + Shift + H | 显示方法层次结构 |
Ctrl + Alt + H | 调用层次 |
F2/Shift + F2 | 跳转到下一个/上一个高亮错误 或 警告位置(必备) |
F4 | 编辑源(必备) |
Alt + Home | 定位/显示到当前文件的 Navigation Bar |
F11 | 添加书签(必备) |
Ctrl + F11 | 选中文件/文件夹,使用助记符设定/取消书签(必备) |
Shift + F11 | 弹出书签显示层(必备) |
Alt + 1,2,3…9 | 显示对应数值的选项卡,其中 1 是 Project 用得最多(必备) |
Ctrl + 1,2,3…9 | 定位到对应数值的书签位置(必备) |
Refactoring
快捷键 | 介绍 |
---|---|
Shift + F6 | 对文件/文件夹 重命名(必备) |
Ctrl + Alt + Shift + T | 打开重构菜单(必备) |
VCS/Local History
快捷键 | 介绍 |
---|---|
Ctrl + K | 版本控制提交项目,需要此项目有加入到版本控制才可用 |
Ctrl + T | 版本控制更新项目,需要此项目有加入到版本控制才可用 |
`Alt + | ` |
Alt + Shift + C | 查看最近操作项目的变化情况列表 |
Alt + Shift + N | 选择/添加 task(必备) |
Live Templates
快捷键 | 介绍 |
---|---|
Ctrl + J | 插入自定义动态代码模板(必备) |
Ctrl + Alt + J | 弹出模板选择窗口,将选定的代码加入动态模板中 |
General
快捷键 | 介绍 |
---|---|
Ctrl + Tab | 编辑窗口切换,如果在切换的过程又加按上 delete,则是关闭对应选中的窗口 |
Ctrl + Alt + Y | 同步、刷新 |
Ctrl + Alt + S | 打开 IntelliJ IDEA 系统设置(必备) |
Ctrl + Alt + Shift + S | 打开当前项目设置(必备) |
Ctrl + Shift + A | 查找动作/设置(必备) |
Ctrl + Shift + F12 | 编辑器最大化(必备) |
Alt + Shift + F | 显示添加到收藏夹弹出层/添加到收藏夹 |
Alt + Shift + I | 查看项目当前文件 |
Intellij IDEA 官方快捷键表
插件
推荐几个比较好用的插件
- Key promoter 快捷键提示
- CamelCase 驼峰式命名和下划线命名交替变化
- CheckStyle-IDEA 代码规范检查
- FindBugs-IDEA潜在 Bug 检查
- MetricsReloaded 代码复杂度检查
- Statistic 代码统计
- JRebel Plugin 热部署
- GsonFormat 把 JSON 字符串直接实例化成类
- Eclipse Code Formatter 如果你以前用的是 IDE,并有自己的一套代码风格配置,可以通过此插件导入到 IDEA
- Alibaba Java Coding Guidelines 阿里 Java 开发规范的静态检查工具
- IDE Features Trainer 官方的新手训练插件
- Markdown Navigator Markdown 插件,适用于喜欢用 markdown 写文档的人
个性化
颜色主题
intellij-colors-solarized 个人觉得这种色彩搭配十分优雅
FAQ
(1)运行时报错
Error running XXX. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun
解决方案:
找到 .idea/libraies/workspace.xml
中的 <component name="PropertiesComponent">
添加一行配置:
1 | <property name="dynamic.classpath" value="true" /> |
参考资料
Mysql 运维
Mysql 运维
如果你的公司有 DBA,那么我恭喜你,你可以无视 Mysql 运维。如果你的公司没有 DBA,那你就好好学两手 Mysql 基本运维操作,行走江湖,防身必备。
安装部署
Windows 安装
(1)下载 Mysql 5.7 免安装版
下载地址:https://dev.mysql.com/downloads/mysql/5.7.html#downloads
(2)解压并创建 my.ini 在根目录
my.ini 文件示例:
1 | [mysqld] |
(3)执行安装命令
在控制台 CMD 中依次执行以下安装命令
1 | cd D:\\Tools\\DB\\mysql\\mysql-5.7.31 |
说明:
mysqld --initialize
会自动初始化创建 data 文件夹并初始化 mysql。mysqld -install
会安装 mysql 服务。
(4)启动服务
在控制台执行 net start mysql
启动服务。
CentOS 安装
本文仅介绍 rpm 安装方式
安装 mysql yum 源
官方下载地址:https://dev.mysql.com/downloads/repo/yum/
(1)下载 yum 源
1 | wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm |
(2)安装 yum repo 文件并更新 yum 缓存
1 | rpm -ivh mysql80-community-release-el7-1.noarch.rpm |
执行结果:
会在 /etc/yum.repos.d/ 目录下生成两个 repo 文件
1 | $ ls | grep mysql |
更新 yum:
1 | yum clean all |
(3)查看 rpm 安装状态
1 | $ yum search mysql | grep server |
通过 yum 安装 mysql 有几个重要目录:
1 | ## 配置文件 |
(4)安装 mysql 服务器
1 | yum install mysql-community-server |
mysql 服务管理
通过 yum 方式安装 mysql 后,本地会有一个名为 mysqld
的 systemd 服务。
其服务管理十分简便:
1 | ## 查看状态 |
初始化数据库密码
查看一下初始密码
1 | $ grep "password" /var/log/mysqld.log |
执行命令:
1 | mysql -uroot -p<临时密码> |
输入临时密码,进入 mysql,如果要修改密码,执行以下指令:
1 | ALTER user 'root'@'localhost' IDENTIFIED BY '你的密码'; |
注:密码强度默认为中等,大小写字母、数字、特殊符号,只有修改成功后才能修改配置再设置更简单的密码
配置远程访问
1 | CREATE USER 'root'@'%' IDENTIFIED BY '你的密码'; |
跳过登录认证
1 | vim /etc/my.cnf |
在 [mysqld] 下面加上 skip-grant-tables
作用是登录时跳过登录认证,换句话说就是 root 什么密码都可以登录进去。
执行 systemctl restart mysqld
,重启 mysql
基本运维
客户端连接
语法:mysql -h<主机> -P<端口> -u<用户名> -p<密码>
如果没有显式指定密码,会要求输入密码才能访问。
【示例】连接本地 Mysql
1 | $ mysql -h 127.0.0.1 -P 3306 -u root -p |
查看连接
连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 show processlist
命令中看到它。客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout
控制的,默认值是 8 小时。
创建用户
1 | CREATE USER 'username'@'host' IDENTIFIED BY 'password'; |
说明:
- username:你将创建的用户名
- host:指定该用户在哪个主机上可以登陆,如果是本地用户可用 localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符
%
- password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器
示例:
1 | CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456'; |
注意:在 Mysql 8 中,默认密码验证不再是
password
。所以在创建用户时,create user 'username'@'%' identified by 'password';
客户端是无法连接服务的。所以,需要加上
IDENTIFIED WITH mysql_native_password
,例如:CREATE USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
查看用户
1 | -- 查看所有用户 |
授权
命令:
1 | GRANT privileges ON databasename.tablename TO 'username'@'host' |
说明:
- privileges:用户的操作权限,如
SELECT
,INSERT
,UPDATE
等,如果要授予所的权限则使用ALL
- databasename:数据库名
- tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用
*
表示,如*.*
示例:
1 | GRANT SELECT, INSERT ON test.user TO 'pig'@'%'; |
注意:
用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:
1 | -- 为指定用户配置指定权限 |
撤销授权
命令:
1 | REVOKE privilege ON databasename.tablename FROM 'username'@'host'; |
说明:
privilege, databasename, tablename:同授权部分
例子:
1 | REVOKE SELECT ON *.* FROM 'pig'@'%'; |
注意:
假如你在给用户'pig'@'%'
授权的时候是这样的(或类似的):GRANT SELECT ON test.user TO 'pig'@'%'
,则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';
命令并不能撤销该用户对 test 数据库中 user 表的SELECT
操作。相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%';
则REVOKE SELECT ON test.user FROM 'pig'@'%';
命令也不能撤销该用户对 test 数据库中 user 表的Select
权限。
具体信息可以用命令SHOW GRANTS FOR 'pig'@'%';
查看。
查看授权
1 | -- 查看用户权限 |
更改用户密码
1 | SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword'); |
如果是当前登陆用户用:
1 | SET PASSWORD = PASSWORD("newpassword"); |
示例:
1 | SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456"); |
备份与恢复
Mysql 备份数据使用 mysqldump 命令。
mysqldump 将数据库中的数据备份成一个文本文件,表的结构和表中的数据将存储在生成的文本文件中。
备份:
备份一个数据库
语法:
1 | mysqldump -h <host> -P<port> -u<username> -p<database> [<table1> <table2> ...] > backup.sql |
host
- Mysql Server 的 hostport
- Mysql Server 的端口username
- 数据库用户dbname
- 数据库名称- table1 和 table2 参数表示需要备份的表的名称,为空则整个数据库备份;
- BackupName.sql 参数表设计备份文件的名称,文件名前面可以加上一个绝对路径。通常将数据库被分成一个后缀名为 sql 的文件
备份多个数据库
1 | mysqldump -u <username> -p --databases <database1> <database2> ... > backup.sql |
备份所有数据库
1 | mysqldump -u <username> -p --all-databases > backup.sql |
恢复一个数据库
Mysql 恢复数据使用 mysql 命令。
语法:
1 | mysql -h <host> -P<port> -u<username> -p<database> < backup.sql |
恢复所有数据库
1 | mysql -u<username> -p --all-databases < backup.sql |
卸载
(1)查看已安装的 mysql
1 | $ rpm -qa | grep -i mysql |
(2)卸载 mysql
1 | yum remove mysql-community-server.x86_64 |
主从节点部署
假设需要配置一个主从 Mysql 服务器环境
- master 节点:192.168.8.10
- slave 节点:192.168.8.11
主节点上的操作
(1)修改配置并重启
执行 vi /etc/my.cnf
,添加如下配置:
1 | [mysqld] |
server-id
- 服务器 ID 号。在主从架构中,每台机器的 ID 必须唯一。log_bin
- 同步的日志路径及文件名,一定注意这个目录要是 mysql 有权限写入的;
修改后,重启 mysql 使配置生效:
1 | systemctl restart mysql |
(2)创建用于同步的用户
进入 mysql 命令控制台:
1 | $ mysql -u root -p |
执行以下 SQL:
1 | -- a. 创建 slave 用户 |
注意:在 Mysql 8 中,默认密码验证不再是
password
。所以在创建用户时,create user 'username'@'%' identified by 'password';
客户端是无法连接服务的。所以,需要加上IDENTIFIED WITH mysql_native_password BY 'password'
补充用户管理 SQL:
1 | -- 查看所有用户 |
(3)加读锁
为了主库与从库的数据保持一致,我们先为 mysql 加入读锁,使其变为只读。
1 | mysql> FLUSH TABLES WITH READ LOCK; |
(4)查看主节点状态
1 | mysql> show master status; |
注意:需要记录下
File
和Position
,后面会用到。
(5)导出 sql
1 | mysqldump -u root -p --all-databases --master-data > dbdump.sql |
(6)解除读锁
1 | mysql> UNLOCK TABLES; |
(7)将 sql 远程传送到从节点上
1 | scp dbdump.sql root@192.168.8.11:/home |
从节点上的操作
(1)修改配置并重启
执行 vi /etc/my.cnf
,添加如下配置:
1 | [mysqld] |
server-id
- 服务器 ID 号。在主从架构中,每台机器的 ID 必须唯一。log_bin
- 同步的日志路径及文件名,一定注意这个目录要是 mysql 有权限写入的;
修改后,重启 mysql 使配置生效:
1 | systemctl restart mysql |
(2)导入 sql
1 | mysql -u root -p < /home/dbdump.sql |
(3)在从节点上建立与主节点的连接
进入 mysql 命令控制台:
1 | $ mysql -u root -p |
执行以下 SQL:
1 | -- 停止从节点服务 |
MASTER_LOG_FILE
和MASTER_LOG_POS
参数要分别与show master status
指令获得的File
和Position
属性值对应。MASTER_HOST
是主节点的 HOST。MASTER_USER
和MASTER_PASSWORD
是在主节点上注册的用户及密码。
(4)启动 slave 进程
1 | mysql> start slave; |
(5)查看主从同步状态
1 | mysql> show slave status\G; |
说明:如果以下两项参数均为 YES,说明配置正确。
Slave_IO_Running
Slave_SQL_Running
(6)将从节点设为只读
1 | mysql> set global read_only=1; |
注:设置 slave 服务器为只读,并不影响主从同步。
慢查询
查看慢查询是否开启
1 | show variables like '%slow_query_log'; |
可以通过 set global slow_query_log
命令设置慢查询是否开启:ON 表示开启;OFF 表示关闭。
1 | set global slow_query_log='ON'; |
查看慢查询时间阈值
1 | show variables like '%long_query_time%'; |
设置慢查询阈值
1 | set global long_query_time = 3; |
隔离级别
查看隔离级别:
1 | mysql> show variables like 'transaction_isolation'; |
服务器配置
大部分情况下,默认的基本配置已经足够应付大多数场景,不要轻易修改 Mysql 服务器配置,除非你明确知道修改项是有益的。
尽量不要使用 Mysql 的缓存功能,因为其要求每次请求参数完全相同,才能命中缓存。这种方式实际上并不高效,还会增加额外开销,实际业务场景中一般使用 Redis 等 key-value 存储来解决缓存问题,性能远高于 Mysql 的查询缓存。
配置文件路径
配置 Mysql 首先要确定配置文件在哪儿。
不同 Linux 操作系统上,Mysql 配置文件路径可能不同。通常的路径为 /etc/my.cnf 或 /etc/mysql/my.cnf 。
如果不知道配置文件路径,可以尝试以下操作:
1 | # which mysqld |
配置项语法
Mysql 配置项设置都使用小写,单词之间用下划线或横线隔开(二者是等价的)。
建议使用固定的风格,这样检索配置项时较为方便。
1 | # 这两种格式等价 |
基本配置模板
一个基本的 Mysql 配置模板大概如下:
1 | [mysqld] |
配置项说明
下面是一个较为详尽的 Mysql 配置文件,各配置项有注释说明:
1 | [mysqld] |
GENERAL
datadir
- mysql 数据文件所在目录socket
- scoket 文件pid_file
- PID 文件user
- 启动 mysql 服务进程的用户port
- 服务端口号,默认3306
default_storage_engine
- mysql 5.1 之后,默认引擎是 InnoDBdefault_time_zone
- 默认时区。中国大部分地区在东八区,即+8:00
character_set_server
- 数据库默认字符集collation_server
- 数据库字符集对应一些排序等规则,注意要和character_set_server
对应
LOG
log_error
- 错误日志文件地址slow_query_log
- 错误日志文件地址
InnoDB
innodb_buffer_pool_size
- InnoDB 使用一个缓冲池来保存索引和原始数据,不像 MyISAM。这里你设置越大,你在存取表里面数据时所需要的磁盘 I/O 越少。- 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的 60%-80%
- 注意别设置的过大,会导致 system 的 swap 空间被占用,导致操作系统变慢,从而减低 sql 查询的效率
- 默认值:128M,建议值:物理内存的 60%-80%
innodb_log_file_size
- 日志文件的大小。默认值:48M,建议值:根据你系统的磁盘空间和日志增长情况调整大小innodb_file_per_table
- 说明:mysql5.7 之后默认开启,意思是,每张表一个独立表空间。默认值 1,开启。innodb_flush_method
- 说明:控制着 innodb 数据文件及 redo log 的打开、刷写模式,三种模式:fdatasync(默认),O_DSYNC,O_DIRECT。默认值为空,建议值:使用 SAN 或者 raid,建议用 O_DIRECT,不懂测试的话,默认生产上使用 O_DIRECTfdatasync
:数据文件,buffer pool->os buffer->磁盘;日志文件,buffer pool->os buffer->磁盘;O_DSYNC
: 数据文件,buffer pool->os buffer->磁盘;日志文件,buffer pool->磁盘;O_DIRECT
: 数据文件,buffer pool->磁盘; 日志文件,buffer pool->os buffer->磁盘;
MyIsam
key_buffer_size
- 指定索引缓冲区的大小,为 MYISAM 数据表开启供线程共享的索引缓存,对 INNODB 引擎无效。相当影响 MyISAM 的性能。- 不要将其设置大于你可用内存的 30%,因为一部分内存同样被 OS 用来缓冲行数据
- 甚至在你并不使用 MyISAM 表的情况下,你也需要仍旧设置起 8-64M 内存由于它同样会被内部临时磁盘表使用。
- 默认值 8M,建议值:对于内存在 4GB 左右的服务器该参数可设置为 256M 或 384M。
- 注意:该参数值设置的过大反而会是服务器整体效率降低!
OTHER
tmp_table_size
- 内存临时表的最大值,默认 16M,此处设置成 128Mmax_heap_table_size
- 用户创建的内存表的大小,默认 16M,往往和tmp_table_size
一起设置,限制用户临时表大小。超限的话,MySQL 就会自动地把它转化为基于磁盘的 MyISAM 表,存储在指定的 tmpdir 目录下,增大 IO 压力,建议内存大,增大该数值。query_cache_type
- 这个系统变量控制着查询缓存功能的开启和关闭,0 表示关闭,1 表示打开,2 表示只要select
中明确指定SQL_CACHE
才缓存。query_cache_size
- 默认值 1M,优点是查询缓存可以极大的提高服务器速度,如果你有大量的相同的查询并且很少修改表。缺点:在你表经常变化的情况下或者如果你的查询原文每次都不同,查询缓存也许引起性能下降而不是性能提升。max_connections
- 最大连接数,可设最大值 16384,一般考虑根据同时在线人数设置一个比较综合的数字,鉴于该数值增大并不太消耗系统资源,建议直接设 10000。如果在访问时经常出现 Too Many Connections 的错误提示,则需要增大该参数值thread_cache
- 当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁。可重用,减小了系统开销。默认值为 9,建议值:两种取值方式,- 方式一,根据物理内存,1G —> 8;2G —> 16; 3G —> 32; >3G —> 64;
- 方式二,根据 show status like ‘threads%’,查看 Threads_connected 值。
open_files_limit
- MySQL 打开的文件描述符限制,默认最小 1024;- 当 open_files_limit 没有被配置的时候,比较 max_connections*5 和 ulimit -n 的值,哪个大用哪个,
- 当 open_file_limit 被配置的时候,比较 open_files_limit 和 max_connections*5 的值,哪个大用哪个
- 注意:仍然可能出现报错信息 Can’t create a new thread;此时观察系统
cat /proc/mysql
进程号/limits,观察进程 ulimit 限制情况 - 过小的话,考虑修改系统配置表,
/etc/security/limits.conf
和/etc/security/limits.d/90-nproc.conf
常见问题
Too many connections
现象
尝试连接 Mysql 时,遇到 Too many connections
错误。
原因
数据库连接线程数超过最大值,访问被拒绝。
解决方案
如果实际连接线程数过大,可以考虑增加服务器节点来分流;如果实际线程数并不算过大,那么可以配置 max_connections
来增加允许的最大连接数。需要注意的是,连接数不宜过大,一般来说,单库每秒有 2000 个并发连接时,就可以考虑扩容了,健康的状态应该维持在每秒 1000 个并发连接左右。
(1)查看最大连接数
1 | mysql> show variables like '%max_connections%'; |
(2)查看服务器响应的最大连接数
1 | mysql> show global status like 'Max_used_connections'; |
(3)临时设置最大连接数
1 | set GLOBAL max_connections=256; |
注意:当服务器重启时,最大连接数会被重置。
(4)永久设置最大连接数
修改 /etc/my.cnf
配置文件,在 [mysqld]
添加以下配置:
1 | max_connections=256 |
重启 mysql 以生效
(5)修改 Linux 最大文件数限制
设置了最大连接数,如果还是没有生效,考虑检查一下 Linux 最大文件数
Mysql 最大连接数会受到最大文件数限制,vim /etc/security/limits.conf
,添加 mysql 用户配置
1 | mysql hard nofile 65535 |
(6)检查 LimitNOFILE
如果是使用 rpm 方式安装 mysql,检查 mysqld.service 文件中的 LimitNOFILE
是否配置的太小。
时区(time_zone)偏差
现象
数据库中存储的 Timestamp 字段值比真实值少了 13 个小时。
原因
- 当 JDBC 与 MySQL 开始建立连接时,会获取服务器参数。
- 当 MySQL 的
time_zone
值为SYSTEM
时,会取system_time_zone
值作为协调时区,若得到的是CST
那么 Java 会误以为这是CST -0500
,因此会给出错误的时区信息(国内一般是CST +0800
,即东八区)。
查看时区方法:
通过 show variables like '%time_zone%';
命令查看 Mysql 时区配置:
1 | mysql> show variables like '%time_zone%'; |
解决方案
方案一
1 | mysql> set global time_zone = '+08:00'; |
方案二
修改 my.cnf
文件,在 [mysqld]
节下增加 default-time-zone='+08:00'
,然后重启。
数据表损坏如何修复
使用 myisamchk 来修复,具体步骤:
- 修复前将 mysql 服务停止。
- 打开命令行方式,然后进入到 mysql 的
bin
目录。 - 执行 myisamchk –recover 数据库所在路 /*.MYI
使用 repair table 或者 OPTIMIZE table 命令来修复,REPAIR TABLE table_name 修复表 OPTIMIZE TABLE table_name 优化表 REPAIR TABLE 用于修复被破坏的表。 OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了 OPTIMIZE TABLE 命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)
数据结构
问题现象:ERROR 1071: Specified key was too long; max key length is 767 bytes
问题原因:Mysql 默认情况下单个列的索引不能超过 767 位(不同版本可能存在差异) 。
解决方法:优化索引结构,索引字段不宜过长。
脚本
这里推荐我写的几个一键运维脚本,非常方便,欢迎使用:
参考资料
- 《高性能 MySQL》
- https://www.cnblogs.com/xiaopotian/p/8196464.html
- https://www.cnblogs.com/bigbrotherer/p/7241845.html
- https://blog.csdn.net/managementandjava/article/details/80039650
- http://www.manongjc.com/article/6996.html
- https://www.cnblogs.com/xyabk/p/8967990.html
- MySQL 8.0 主从(Master-Slave)配置
- Mysql 主从同步实战
- MySQL 备份和恢复机制
- Mysql 配置文件/etc/my.cnf 解析
iptables
Iptables 应用
iptables 是一个配置 Linux 内核 防火墙 的命令行工具,是 netfilter 项目的一部分。 可以直接配置,也可以通过许多前端和图形界面配置。
iptables 也经常代指该内核级防火墙。iptables 用于 ipv4,ip6tables 用于 ipv6。
nftables 已经包含在 Linux kernel 3.13 中,以后会取代 iptables 成为主要的 Linux 防火墙工具。
环境:CentOS7
简介
iptables 可以检测、修改、转发、重定向和丢弃 IPv4 数据包。
过滤 IPv4 数据包的代码已经内置于内核中,并且按照不同的目的被组织成 表 的集合。表 由一组预先定义的 链 组成,链包含遍历顺序规则。每一条规则包含一个谓词的潜在匹配和相应的动作(称为 目标),如果谓词为真,该动作会被执行。也就是说条件匹配。
安装 iptables
(1)禁用 firewalld
CentOS 7 上默认安装了 firewalld 作为防火墙,使用 iptables 建议关闭并禁用 firewalld。
1 | systemctl stop firewalld |
(2)安装 iptables
1 | yum install -y iptables-services |
(3)服务管理
- 查看服务状态:
systemctl status iptables
- 启用服务:
systemctl enable iptables
- 禁用服务:
systemctl disable iptables
- 启动服务:
systemctl start iptables
- 重启服务:
systemctl restart iptables
- 关闭服务:
systemctl stop iptables
命令
基本语法:
1 | iptables(选项)(参数) |
基本选项说明:
参数 | 作用 |
---|---|
-P | 设置默认策略:iptables -P INPUT (DROP |
-F | 清空规则链 |
-L | 查看规则链 |
-A | 在规则链的末尾加入新规则 |
-I | num 在规则链的头部加入新规则 |
-D | num 删除某一条规则 |
-s | 匹配来源地址 IP/MASK,加叹号”!”表示除这个 IP 外。 |
-d | 匹配目标地址 |
-i | 网卡名称 匹配从这块网卡流入的数据 |
-o | 网卡名称 匹配从这块网卡流出的数据 |
-p | 匹配协议,如 tcp,udp,icmp |
–dport num | 匹配目标端口号 |
–sport num | 匹配来源端口号 |
顺序:
1 | iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作 |
iptables 示例
清空当前的所有规则和计数
1 | iptables -F # 清空所有的防火墙规则 |
配置允许 ssh 端口连接
1 | iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT |
允许本地回环地址可以正常使用
1 | iptables -A INPUT -i lo -j ACCEPT |
设置默认的规则
1 | iptables -P INPUT DROP # 配置默认的不让进 |
配置白名单
1 | iptables -A INPUT -p all -s 192.168.1.0/24 -j ACCEPT # 允许机房内网机器可以访问 |
开启相应的服务端口
1 | iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 开启80端口,因为web对外都是这个端口 |
保存规则到配置文件中
1 | cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak # 任何改动之前先备份,请保持这一优秀的习惯 |
列出已设置的规则
iptables -L [-t 表名][链名]
- 四个表名
raw
,nat
,filter
,mangle
- 五个规则链名
INPUT
、OUTPUT
、FORWARD
、PREROUTING
、POSTROUTING
- filter 表包含
INPUT
、OUTPUT
、FORWARD
三个规则链
1 | iptables -L -t nat # 列出 nat 上面的所有规则 |
清除已有规则
1 | iptables -F INPUT # 清空指定链 INPUT 上面的所有规则 |
删除已添加的规则
1 | # 添加一条规则 |
将所有 iptables 以序号标记显示,执行:
1 | iptables -L -n --line-numbers |
比如要删除 INPUT 里序号为 8 的规则,执行:
1 | iptables -D INPUT 8 |
开放指定的端口
1 | iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT #允许本地回环接口(即运行本机访问本机) |
屏蔽 IP
1 | iptables -A INPUT -p tcp -m tcp -s 192.168.0.8 -j DROP # 屏蔽恶意主机(比如,192.168.0.8 |
指定数据包出去的网络接口
只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。
1 | iptables -A FORWARD -o eth0 |
查看已添加的规则
1 | iptables -L -n -v |
启动网络转发规则
公网210.14.67.7
让内网192.168.188.0/24
上网
1 | iptables -t nat -A POSTROUTING -s 192.168.188.0/24 -j SNAT --to-source 210.14.67.127 |
端口映射
本机的 2222 端口映射到内网 虚拟机的 22 端口
1 | iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222 -j DNAT --to-dest 192.168.188.115:22 |
字符串匹配
比如,我们要过滤所有 TCP 连接中的字符串test
,一旦出现它我们就终止这个连接,我们可以这么做:
1 | iptables -A INPUT -p tcp -m string --algo kmp --string "test" -j REJECT --reject-with tcp-reset |
阻止 Windows 蠕虫的攻击
1 | iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe" |
防止 SYN 洪水攻击
1 | iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT |
参考资料
Spring Framework 综述
Spring Framework 综述
Spring Framework 简介
Spring Framework 是最受欢迎的企业级 Java 应用程序开发框架。用于构建企业级应用的轻量级、一站式解决方案。
当谈论到大小和透明度时, Spring 是轻量级的。 Spring 框架的基础版本是在 2 MB 左右的。
Spring 框架的核心特性可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。
Spring Framework 设计理念如下:
- 力争让选择无处不在
- 体现海纳百川的精神
- 保持后向兼容性
- 专注 API 设计
- 追求严苛的代码质量
为什么使用 Spring
下面列出的是使用 Spring 框架主要的好处:
- Spring 可以使开发人员使用 POJOs 开发企业级的应用程序。只使用 POJOs 的好处是你不需要一个 EJB 容器产品,比如一个应用程序服务器,但是你可以选择使用一个健壮的 servlet 容器,比如 Tomcat 或者一些商业产品。
- Spring 在一个单元模式中是有组织的。即使包和类的数量非常大,你只需要选择你需要的部分,而忽略剩余的那部分。
- Spring 不会让你白费力气做重复工作,它真正的利用了一些现有的技术,像几个 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,其他视图技术。
- 测试一个用 Spring 编写的应用程序很容易,因为 environment-dependent 代码被放进了这个框架中。此外,通过使用 JavaBean-style POJOs,它在使用依赖注入注入测试数据时变得更容易。
- Spring 的 web 框架是一个设计良好的 web MVC 框架,它为 web 框架,比如 Structs 或者其他工程上的或者很少受欢迎的 web 框架,提供了一个很好的供替代的选择。
- 为将特定技术的异常(例如,由 JDBC、Hibernate,或者 JDO 抛出的异常)翻译成一致的, Spring 提供了一个方便的 API,而这些都是未经检验的异常。
- 轻量级的 IOC 容器往往是轻量级的,例如,特别是当与 EJB 容器相比的时候。这有利于在内存和 CPU 资源有限的计算机上开发和部署应用程序。
- Spring 提供了一个一致的事务管理界面,该界面可以缩小成一个本地事务(例如,使用一个单一的数据库)和扩展成一个全局事务(例如,使用 JTA)。
核心思想
Spring 最核心的两个技术思想是:IoC 和 Aop
IoC
IoC
即 Inversion of Control
,意为控制反转。
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。
到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。
依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。
Aop
Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。
在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。
Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。
Spring 体系结构
Spring 当前框架有20个 jar 包,大致可以分为6大模块:
- 为什么使用 Spring
- 核心思想
- 2.1. IoC
- 2.2. Aop
- Spring 体系结构
- 3.1. Core Container
- 3.1.1. BeanFactory
- 3.1.2. ApplicationContext
- 3.2. AOP and Instrumentation
- 3.3. Messaging
- 3.4. Data Access / Integaration
- 3.5. Web
- 3.6. Test
- 术语
Spring 框架提供了非常丰富的功能,因此整个架构也很庞大。
在我们实际的应用开发中,并不一定要使用所有的功能,而是可以根据需要选择合适的 Spring 模块。
Core Container
IoC 容器是 Spring 框架的核心。spring 容器使用依赖注入管理构成应用的组件,它会创建相互协作的组件之间的关联。毫无疑问,这些对象更简单干净,更容易理解,也更容易重用和测试。
Spring 自带了几种容器的实现,可归纳为两种类型:
BeanFactory
由 org.springframework.beans.factory.BeanFactory 接口定义。
它是最简单的容器,提供基本的 DI 支持。
ApplicationContext
由 org.springframework.context.ApplicationContext 接口定义。
它是基于 BeanFactory 之上构建,并提供面向应用的服务,例如从属性文件解析文本信息的能力,以及发布应用事件给感兴趣的事件监听者的能力。
注:Bean 工厂对于大多数应用来说往往太低级了,所以应用上下文使用更广泛。推荐在开发中使用应用上下文容器。
Spring 自带了多种应用上下文,最可能遇到的有以下几种:ClassPathXmlApplicationContext
:从类路径下的 XML 配置文件中加载上下文定义,把应用上下文定义文件当做类资源。FileSystemXmlApplicationContext
:读取文件系统下的 XML 配置文件并加载上下文定义。XmlWebApplicationContext
:读取 Web 应用下的 XML 配置文件并装载上下文定义。
范例
1 | ApplicationContext context = new FileSystemXmlApplicationContext("D:\Temp\build.xml"); |
可以看到,加载 FileSystemXmlApplicationContext
和 ClassPathXmlApplicationContext
十分相似。
差异在于:前者在指定文件系统路径下查找 build.xml 文件;而后在所有类路径(包含 JAR 文件)下查找 build.xml 文件。
通过引用应用上下文,可以很方便的调用 getBean() 方法从 Spring 容器中获取 Bean。
相关 jar 包
spring-core
,spring-beans
, 提供框架的基础部分,包括 IoC 和依赖注入特性。spring-context
, 在spring-core
,spring-beans
基础上构建。它提供一种框架式的访问对象的方法。它也支持类似 Java EE 特性,例如:EJB,JMX 和基本 remoting。ApplicationContext 接口是它的聚焦点。springcontext-support
, 集成第三方库到 Spring application context。spring-expression
,提供一种强有力的表达语言在运行时来查询和操纵一个对象图。
AOP and Instrumentation
相关 jar 包
spring-aop
,提供了对面向切面编程的丰富支持。spring-aspects
,提供了对 AspectJ 的集成。spring-instrument
,提供了对类 instrumentation 的支持和类加载器。spring-instrument-tomcat
,包含了 Spring 对 Tomcat 的 instrumentation 代理。
Messaging
相关 jar 包
spring-messaging
,包含 spring 的消息处理功能,如 Message,MessageChannel,MessageHandler。
Data Access / Integaration
Data Access/Integration 层包含了 JDBC / ORM / OXM / JMS 和 Transaction 模块。
相关 jar 包
spring-jdbc
,提供了一个 JDBC 抽象层。spring-tx
,支持编程和声明式事务管理类。spring-orm
,提供了流行的对象关系型映射 API 集,如 JPA,JDO,Hibernate。spring-oxm
,提供了一个抽象层以支持对象/XML 映射的实现,如 JAXB,Castor,XMLBeans,JiBX 和 XStream.spring-jms
,包含了生产和消费消息的功能。
Web
相关 jar 包
spring-web
,提供了基本的面向 web 的功能,如多文件上传、使用 Servlet 监听器的 Ioc 容器的初始化。一个面向 web 的应用层上下文。spring-webmvc
,包括 MVC 和 REST web 服务实现。spring-webmvc-portlet
,提供在 Protlet 环境的 MVC 实现和spring-webmvc
功能的镜像。
Test
相关 jar 包
spring-test
,以 Junit 和 TestNG 来支持 spring 组件的单元测试和集成测试。
术语
- 应用程序:是能完成我们所需要功能的成品,比如购物网站、OA 系统。
- 框架:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
- 非侵入式设计:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
- 轻量级及重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
- POJO:POJO(Plain Old Java Objects)简单的 Java 对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它 Java 框架的类或接口。
- 容器:在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
- 控制反转:即 Inversion of Control,缩写为 IoC,控制反转还有一个名字叫做依赖注入(Dependency Injection),就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。
- JavaBean:一般指容器管理对象,在 Spring 中指 Spring IoC 容器管理对象。
计算机网络面试总结
计算机网络面试总结
如果你不是从事于通信领域,面试时问及计算机网络的知识,一般也就限定在:HTTP(含 HTTPS、Cookie、Session)、TCP、UDP、Socket 这些
综合
计算机网络如何分层?
❓ 问题:计算机网络如何分层?各层的作用是什么?各层的主要协议、设备分别是什么?
这是学习计算机网络知识宏观层面必须要了解的核心点。知道了这些,对于网络的体系结构就基本上了解了。
计算机网络分层一般有三种划分体系:OSI 分层;五层协议分层;TCP/IP 协议分层。
- OSI 的七层体系结构概念清楚,理论完整,但是比较复杂且不实用,所以并不流行。
- 五层协议分层是一种折中方案,在现实中更为流行。
物理层
物理层(Physical Layer)只接收和发送一串比特(bit)流,不考虑信息的意义和信息结构。
扩展阅读:计算机网络之物理层
- 关键词:调制、解调、数字信号、模拟信号、通信媒介、信道复用
- 数据单元:比特流。
- 典型设备:光纤、同轴电缆、双绞线、中继器和集线器。
数据链路层
网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,数据链路层(Data Link Layer)就是为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧。
扩展阅读:计算机网络之数据链路层
- 关键词:点对点信道、广播信道、
PPP
、CSMA/CD
、局域网、以太网、MAC
、适配器、集线器、网桥、交换机 - 主要协议:
PPP
、CSMA/CD
等。 - 数据单元:帧(frame)。
- 典型设备:二层交换机、网桥、网卡。
网络层
网络层(network layer)为分组交换网上的不同主机提供通信服务。在发送数据时,网络层把运输层产生的报文段或用户数据报封装成分组或包进行传送。
扩展阅读:计算机网络之网络层
- 关键词:
IP
、ICMP
、ARP
、路由 - 主要协议:
IP
。 - 数据单元:IP 数据报(packet)。
- 典型设备:网关、路由器。
传输层
传输层(transport layer)为两台主机中进程间的通信提供通用的数据传输服务。
扩展阅读:计算机网络之传输层
- 关键词:
UDP
、TCP
、滑动窗口、拥塞控制、三次握手 - 主要协议:
TCP
、UDP
。 - 数据单元:报文段(segment)或用户数据报。
\会话层~~
~~会话层(Session Layer)不参与具体的传输,它提供包括访问验证和会话管理在内的建立和维护应用之间通信的机制。~~
\表示层~~
~~表示层(Presentation Layer)是为在应用过程之间传送的信息提供表示方法的服务,它关心的只是发出信息的语法与语义。表示层要完成某些特定的功能,主要有不同数据编码格式的转换,提供数据压缩、解压缩服务,对数据进行加密、解密。~~
应用层
应用层(application layer)通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程间通信和交互的规则。
扩展阅读:计算机网络之应用层
- 关键词:
HTTP
、DNS
、FTP
、TELNET
、DHCP
- 主要协议:
HTTP
、DNS
、SMTP
、Telnet
、FTP
、SNMP
等。 - 数据单元:报文(message)。
HTTP
扩展阅读:超文本传输协议 HTTP
DNS
扩展阅读:域名系统协议 DNS
TCP/UDP
扩展阅读:传输控制协议 TCP,用户数据报协议 UDP
什么是 TCP?
TCP(Transmission Control Protocol),即传输控制协议,它是一种面向连接的
、可靠的
、基于字节流的
传输层通信协议。
TCP 的特性是什么?
面向连接的
- 面向连接是指 TCP 需要通过三次握手、四次挥手原则建立和断开双向连接。可靠的
- 可靠是指 TCP 传输的数据包保证以原始顺序到达目的地,且数据包不被损坏。为了实现这点,TCP 通过以下技术来保证:- 数据包的序列号和校验码
- 确认包和自动重传
- 如果发送者没有收到正确的响应,它将重新发送数据包。如果多次超时,连接就会断开。
- TCP 实行流量控制和拥塞控制。这些确保措施会导致延迟,而且通常导致传输效率比 UDP 低。
基于字节流的
- 虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序看成是一连串的无结构的字节流。TCP 有一个缓冲,当应用程序传送的数据块太长,TCP 就可以把它划分短一些再传送。如果应用程序一次只发送一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去。
- 在 TCP 建立连接前两次握手的 SYN 报文中选项字段的 MSS 值,通信双方商定通信的最大报文长度。如果应用层交付下来的数据过大,就会对数据分段,然后发送;否则通过滑动窗口来控制通信双发的数据。
TCP 三次握手
❓ 问题:三次握手有什么用?什么是三次握手?为什么需要三次握手?
(1)三次握手有什么用?
- 三次握手负责建立 TCP 双向连接。
(2)什么是三次握手?
如上图所示,三次握手流程如下:
- 第一次握手 - 客户端向服务端发送带有 SYN 标志的数据包。
- 第二次握手 - 服务端向客户端发送带有 SYN/ACK 标志的数据包。
- 第三次握手 - 客户端向服务端发送带有带有 ACK 标志的数据包。
至此,TCP 三次握手完成,客户端与服务端已建立双向连接。
💡 说明:SYN 为 synchronize 的缩写,ACK 为 acknowledgment 的缩写。
(3)为什么需要三次握手?
为了便于说明,假设客户端为 A, 服务端为 B。
- 第一次握手,A 向 B 发同步消息。B 收到消息后,B 认为:A 发消息没问题;B 收消息没问题。
- 第二次握手,B 向 A 发同步消息和确认消息。A 收到消息后,A 认为:A 发消息、收消息都没问题;B 发消息、收消息都没问题。但是,此时 B 不确定自己发消息是否没问题,所以就需要第三次握手。
- 第三次握手,A 向 B 发确认消息。B 收到消息后。B 认为:B 发消息没问题。
TCP 四次挥手
❓ 问题:四次挥手有什么用?什么是四次挥手?为什么建立连接是三次握手,关闭连接确是四次挥手呢?
(1)四次挥手有什么用?
- 四次挥手负责断开 TCP 连接。
(2)什么是四次挥手?
如上图所示,四次挥手流程如下:
- 第一次挥手 - 客户端向服务端发送一个 FIN 包,用来关闭客户端到服务端的数据传送。
- 第二次挥手 - 服务端收到这个 FIN 包,向客户端发送一个 ACK 包,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号。
- 第三次挥手 - 服务端关闭与客户端的连接,向客户端发送一个 FIN 包。
- 第四次挥手 - 客户端向服务端发送 ACK 包,并将确认序号设置为收到序号加 1。
(3)为什么建立连接是三次握手,关闭连接确是四次挥手呢?
- 建立连接的时候, 服务器在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。
- 而关闭连接时,服务器收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送,从而导致多了一次。
TCP 滑动窗口
❓ 问题:什么是滑动窗口?滑动窗口原理是什么?
什么是滑动窗口?
滑动窗口是 TCP 的一种控制网络流量的技术。
TCP 必需要解决的可靠传输以及包乱序(reordering)的问题,所以,TCP 必需要知道网络实际的数据处理带宽或是数据处理速度,这样才不会引起网络拥塞,导致丢包。
TCP 头里有一个字段叫 Window,又叫 Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
滑动窗口原理是什么?
- 已发送已确认 - 数据流中最早的字节已经发送并得到确认。这些数据是站在发送端的角度来看的。上图中的 31 个字节已经发送并确认。
- 已发送但尚未确认 - 已发送但尚未得到确认的字节。发送方在确认之前,不认为这些数据已经被处理。上图中的 32 ~ 45 字节为第 2 类。
- 未发送而接收方已 Ready - 设备尚未将数据发出 ,但接收方根据最近一次关于发送方一次要发送多少字节确认自己有足够空间。发送方会立即尝试发送。上图中的 46 ~ 51 字节为第 3 类。
- 未发送而接收方 Not Ready - 由于接收方 not ready,还不允许将这部分数据发出。上图中的 52 以后的字节为第 4 类。
这张图片相对于上一张图片,滑动窗口偏移了 5 个字节,意味着有 5 个已发送的字节得到了确认。
TCP 重传机制
❓ 问题:为什么需要重传机制?TCP 有哪些重传机制,原理是什么?
TCP 要保证所有的数据包都可以到达,所以,必需要有重传机制。
TCP 重传机制主要有两种:
- 超时重传机制
- 快速重传机制
(1)超时重传机制
超时重传机制是指:发送数据包在一定的时间周期内没有收到相应的 ACK,等待一定的时间,超时之后就认为这个数据包丢失,就会重新发送。这个等待时间被称为 RTO(Retransmission TimeOut),即重传超时时间。
没有确认的数据包不会从窗口中移走,定时器在重传时间到期内,每个片段的位置不变。
这种机制的重点是 RTO 的设置:
- RTO 设长了,重发就慢,丢了老半天才重发,没有效率,性能差;
- RTO 设短了,会导致可能并没有丢就重发。于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发
(2)快速重传机制
快速重传机制,实现了另外的一种丢包评定标准,即如果连续收到 3 次重复 ACK,发送方就认为这个 seq 的包丢失了,立刻进行重传。
当接收方收到乱序片段时,需要重复发送 ACK。
SpringBoot 之发送邮件
SpringBoot 之发送邮件
简介
Spring Boot 收发邮件最简便方式是通过 spring-boot-starter-mail
。
1 | <dependency> |
spring-boot-starter-mail 本质上是使用 JavaMail(javax.mail)。如果想对 JavaMail 有进一步了解,可以参考: JavaMail 使用指南
API
Spring Framework 提供了一个使用 JavaMailSender
接口发送电子邮件的简单抽象,这是发送邮件的核心 API。
JavaMailSender
接口提供的 API 如下:
配置
Spring Boot 为 JavaMailSender
提供了自动配置以及启动器模块。
如果 spring.mail.host
和相关库(由 spring-boot-starter-mail 定义)可用,则 Spring Boot 会创建默认 JavaMailSender
(如果不存在)。可以通过 spring.mail
命名空间中的配置项进一步自定义发件人。
特别是,某些默认超时值是无限的,您可能希望更改它以避免线程被无响应的邮件服务器阻塞,如以下示例所示:
1 | spring.mail.properties.mail.smtp.connectiontimeout=5000 |
也可以使用 JNDI 中的现有会话配置 JavaMailSender
:
1 | spring.mail.jndi-name=mail/Session |
以下为 Spring Boot 关于 Mail 的配置:
有关更多详细信息,请参阅 MailProperties
。
1 | # Email (MailProperties) |
实战
引入依赖
1 | <dependencies> |
配置邮件属性
在 src/main/resources
目录下添加 application-163.properties
配置文件,内容如下:
1 | spring.mail.host = smtp.163.com |
注:需替换有效的 spring.mail.username
、spring.mail.password
。
application-163.properties
配置文件表示使用 163 邮箱时的配置,为了使之生效,需要通过 spring.profiles.active = 163
来激活它。
在 src/main/resources
目录下添加 application.properties
配置文件,内容如下:
1 | spring.profiles.active = 163 |
Java 代码
首先,需要读取部分配置属性,方法如下:
1 | import org.springframework.boot.context.properties.ConfigurationProperties; |
接着,定义一个邮件参数实体类(使用 lombok 简化了 getter、setter):
1 | import lombok.Data; |
接着,实现发送邮件的功能接口:
1 | import com.github.dozermapper.core.Mapper; |
示例源码
示例源码:spring-boot-mail
参考资料
SpringBoot 之 Profile
SpringBoot 之 Profile
一个应用为了在不同的环境下工作,常常会有不同的配置,代码逻辑处理。Spring Boot 对此提供了简便的支持。
关键词:
@Profile
、spring.profiles.active
区分环境的配置
properties 配置
假设,一个应用的工作环境有:dev、test、prod
那么,我们可以添加 4 个配置文件:
applcation.properties
- 公共配置application-dev.properties
- 开发环境配置application-test.properties
- 测试环境配置application-prod.properties
- 生产环境配置
在 applcation.properties
文件中可以通过以下配置来激活 profile:
1 | spring.profiles.active = test |
yml 配置
与 properties 文件类似,我们也可以添加 4 个配置文件:
applcation.yml
- 公共配置application-dev.yml
- 开发环境配置application-test.yml
- 测试环境配置application-prod.yml
- 生产环境配置
在 applcation.yml
文件中可以通过以下配置来激活 profile:
1 | spring: |
此外,yml 文件也可以在一个文件中完成所有 profile 的配置:
1 | # 激活 prod |
注意:不同 profile 之间通过 ---
分割
区分环境的代码
使用 @Profile
注解可以指定类或方法在特定的 Profile 环境生效。
修饰类
1 | @Configuration |
修饰注解
1 | @Target(ElementType.TYPE) |
修饰方法
1 | @Configuration |
激活 profile
插件激活 profile
1 | spring-boot:run -Drun.profiles=prod |
main 方法激活 profile
1 | --spring.profiles.active=prod |
jar 激活 profile
1 | java -jar -Dspring.profiles.active=prod *.jar |
在 Java 代码中激活 profile
直接指定环境变量来激活 profile:
1 | System.setProperty("spring.profiles.active", "test"); |
在 Spring 容器中激活 profile:
1 | AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
示例源码
示例源码:spring-boot-profile
参考资料
spring-boot-async
SpringBoot 教程之处理异步请求
@EnableAsync
注解
要使用 @Async
,首先需要使用 @EnableAsync
注解开启 Spring Boot 中的异步特性。
1 | @Configuration |
更详细的配置说明,可以参考:AsyncConfigurer
@Async
注解
支持的用法
(1)无入参无返回值方法
您可以用 @Async
注解修饰方法,这表明这个方法是异步方式调用。换句话说,程序在调用此方法时会立即返回,而方法的实际执行发生在已提交给 Spring TaskExecutor
的任务中。在最简单的情况下,您可以将注解应用于返回 void 的方法,如以下示例所示:
1 | @Async |
(2)有入参无返回值方法
与使用 @Scheduled
注释注释的方法不同,这些方法可以指定参数,因为它们在运行时由调用者以“正常”方式调用,而不是由容器管理的调度任务调用。例如,以下代码是 @Async
注解的合法应用:
1 | @Async |
(3)有入参有返回值方法
甚至可以异步调用返回值的方法。但是,这些方法需要具有 Future
类型的返回值。这仍然提供了异步执行的好处,以便调用者可以在调用 Future
上的 get()
之前执行其他任务。以下示例显示如何在返回值的方法上使用@Async
:
1 | @Async |
不支持的用法
@Async
不能与生命周期回调一起使用,例如 @PostConstruct
。
要异步初始化 Spring bean,必须使用单独的初始化 Spring bean,然后在目标上调用 @Async
带注释的方法,如以下示例所示:
1 | public class SampleBeanImpl implements SampleBean { |
明确指定执行器
默认情况下,在方法上指定 @Async
时,使用的执行器是在启用异步支持时配置的执行器,即如果使用 XML 或 AsyncConfigurer
实现(如果有),则为 annotation-driven
元素。但是,如果需要指示在执行给定方法时应使用默认值以外的执行器,则可以使用 @Async
注解的 value 属性。以下示例显示了如何执行此操作:
1 | @Async("otherExecutor") |
在这种情况下,“otherExecutor”可以是 Spring 容器中任何 Executor bean 的名称,也可以是与任何 Executor 关联的限定符的名称(例如,使用 <qualifier>
元素或 Spring 的 @Qualifier
注释指定) )。
管理 @Async
的异常
当 @Async
方法的返回值类型为 Future
型时,很容易管理在方法执行期间抛出的异常,因为在调用 get
结果时会抛出此异常。但是,对于返回值类型为 void 型的方法,异常不会被捕获且无法传输。您可以提供 AsyncUncaughtExceptionHandler
来处理此类异常。以下示例显示了如何执行此操作:
1 | public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { |
默认情况下,仅记录异常。您可以使用 AsyncConfigurer
或 <task:annotation-driven />
XML 元素定义自定义 AsyncUncaughtExceptionHandler
。
示例源码
示例源码:spring-boot-async