了解 Jenkins 持续集成系统
随着软件开发复杂度的不断提高,团队成员之间如何更好地协同工作以确保软件开发的质量,已经慢慢成为开发过程中不可回避的问题。Jenkins 自动化部署可以解决集成、测试、部署等重复性的工作,工具集成的效率明显高于人工操作;并且持续集成可以更早的获取代码变更的信息,从而可以更早的进入测试阶段;并且能够更早的发现问题,这样解决问题的成本就会显著下降。
持续集成缩短了从开发、集成、测试、部署各个环节的时间,从而也缩短了中间出现的等待时间。持续集成也意味着开发、集成、测试、部署得以持续。所以,当配置完 Jenkins 持续集成持续交付环境后,就可以把发布的任务交给集成服务器去处理了。本章将使用Maven(Ant)等来实现 Java 项目自动化构建发布部署。这些工具可以帮助在构建过程中实现自动化发布、回滚等动作。
一、什么是 Jenkins
Jenkins 是一个功能强大的应用程序,允许持续集成和持续交付项目(持续部署),无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成 Jenkins 可以用于一些测试和部署技术。
Jenkins 原名 Hudson,2011 年改为现在的名字,它是一个开源的实现持续集成的软件工具。官方网站网址:https://jenkins.io/。Jenkins 能实时监控持续集成过程中所存在的问题,提供详细的日志文件和提醒功能,还能通过图表的形式,形象地展示项目构建的趋势和稳定性。
Jenkins 是一个开源软件项目,是基于 Java 开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。
jenkins 提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更为重要的业务逻辑实现上。同时 enkins 能实时监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用图表的形式形象地展示项目构建的趋势和稳定性。
Jenkins 可以构建一个自动化的持续集成环境可以使用它来“自动化”编译、打包、分发部署应用,它兼容 ant、maven、gradle 等多种第三方构建工具,同时与 svn、git 能无缝集成,也支持直接与知名源代码托管网站,如 github、bitbucket 直接集成。
1.为什么要用 Jenkins
目前持续集成(CI)已成为当前许多软件开发团队在整个软件开发生命周期内侧重于保证代码质量的常见做法。它是一种实践,旨在缓和和稳固软件的构建过程。并且能够帮助您的开发团队应对如下挑战:
(1)软件构建自动化
配置完成后,CI系统会依照预先制定的时间表,或者针对某一特定事件,对目标软件进行构建。
(2)构建可持续的自动化检查
CI系统能持续地获取新增或修改后签入的源代码,也就是说,当软件开发团队需要周期性的检查新增或修改后的代码时,CI系统会不断确认这些新代码是否破坏了原有软件的成功构建。这减少了开发者们在检查彼此相互依存的代码中变化情况需要花费的时间和精力(说直接一点也是钱啊,呵呵)。
(3)构建可持续的自动化测试
构建检查的扩展部分,构建后执行预先制定的一套测试规则,完成后触发通知(Emai1,Rss 等等)给相关的当事人。
(4)生成后后续过程的自动化
当自动化检查和测试成功完成,软件构建的周期中可能也需要一些额外的任务,诸如生成文档、打包软件、部署构件到一个运行环境或者软件仓库。这样,构件才能更迅速地提供给用户使用。
2.Jenkins 的特点
Jenkins 包含以下几个特点:
- 易安装:从官网仅需要下载一个 jenkins.war 文件后,直接运行,无需额外的安装,更无需安装数据库;
- 易配置:提供友好的 GUI 配置界面;
- 变更支持:Jenkins 能从代码仓库(SVN /Git)中获取并产生代码更新列表,并显示到编译输出信息中:
- 支持永久链接:用户是通过 web 来访问 Jenkins 的,而这些 web 页面的链接地址都是永久链接地址,可以在各种文档中直接使用该链接;
- 集成 E-Mai1/RSS/IM:当完成一次集成后,可通过这些工具实时收取集成结果(构建一次集成需要花费一定时间,有了这个功能,就可以在等待结果过程中,干别的事情);
- JUnit/TestNG 测试报告:是以图表等形式提供详细的测试报表功能;
- 支持分布式构建:Jenkins 可以把集成构建等工作分发到多台计算机中完成:
- 文件指纹信息:Jenkins 会保存构建集成所产生的 jars 文件、集成构建使用了哪个版本的jars 文件等构建记录;
- 支持第三方插件:Jenkins 支持第三方插件,这使得enkins 功能变得越来越强大
3.什么是 CI/CD
持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
持续部署(continuous deployment)是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率,让 engineering productivity 最大化。
持续交付(Continuous delivery),是一种软件工程手法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以释出的状况。它的目标在于让软件的建置、测试与释出变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。
4.持续集成的特点
持续集成是一个自动化的、周期性的集成测试过程,检出代码、编译构建、运行测试、结果记录、测试统计等过程都是自动完成的,无需人工干预。持续集成需要有专门的集成服务器来执行集成构建操作,同时需要有代码托管工具的支持。
5.持续集成的工作原理
Jenkins 的工作原理是先将源代码从 SVN/Git 版本控制系统中拷贝一份到本地,然后根据设置的脚本进行 build(构建)。整个系统的关键就是 build 脚本,build 脚本告诉 Jenkins 在一次集成中需要执行的任务。如下图所示。
二、Jenkins的部署
1.设备列表
2.案列拓扑
三、Jenkins 基本环境的安装与设置
1.安装docker
Jenkins 持续集成环境可以和 Harbor 镜像仓库、docker 主机、kubernetes 等共同建立一个流水线环境,在这种环境下,Jenkins 可以将 maven 项目打包为镜像,并将镜像推送至 Harbor,考虑到如果需要在 Jenkins 主机上生成镜像并推送至 Harbor,Jenkins 主机就需要有一个 docker 环境。
具体安装步骤,参考 docker 相关课程。如果已有 docker 环境,此步骤可以略过。
2.操作系统设置
[root@localhost ~]# hostnamectl set-hostname jenkins
[root@localhost ~]# bash
systemctl stop firewalld && systemctl disable firewalld
systemctl stop NetworkManager && systemctl disable NetworkManager
sed -i '/^SELINUX=/s/enforcing/disabled/' /etc/selinux/config
setenforce 0
3.安装git
为了让 Jenkins 支持从 Gitlab 拉取源码,需要安装 Git 插件以及在 centos7 上安装 Git 工具。
[root@jenkins ~]# yum -y install git
4. 安装 java 环境
(1)安装java
[root@jenkins ~]# yum -y install fontconfig
[root@jenkins ~]# tar zxvf jdk-11.0.23_linux-x64_bin.tar.gz
[root@jenkins ~]# mv jdk-11.0.23 /usr/local/java
注意:
Fontconfig 是一款字体配置工具,它允许用户在 Linux、macOs 和 windows 等操作系统上配置字体。Fontconfig,的设计目标是提供一个易于使用的命令行工具,用于管理字体文件和配置字体。这个包是Jenkins 的依赖包,必须安装,否则,Jenkins 无法启动。
(2)设置 java 的环境变量
[root@jenkins ~]# vim /etc/profile
export JAVA_HOME=/usr/local/java
export CLASSPATH=$JAVA_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH
[root@jenkins ~]# source /etc/profile
(3)查看java版本
[root@jenkins ~]# java -version
java version "11.0.23" 2024-04-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.23+7-LTS-222)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.23+7-LTS-222, mixed mode)
5.安装tomcat
[root@jenkins ~]# tar zxvf apache-tomcat-9.0.8.tar.gz
[root@jenkins ~]# mv apache-tomcat-9.0.8 /usr/local/tomcat
6. 为 Jenkins 安装 maven 环境
(1)安装maven
[root@jenkins ~]# tar zxvf apache-maven-3.8.6-bin.tar.gz
[root@jenkins ~]# mv apache-maven-3.8.6 /usr/local/tomcat
(2)设置 java 和 maven 的环境变量
[root@jenkins ~]# vim /etc/profile
export JAVA_HOME=/usr/local/java
export CLASSPATH=$JAVA_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH
export MAVEN_HOME=/usr/local/maven
export PATH=$PATH:$MAVEN_HOME/bin
[root@jenkins ~]# source /etc/profile
(3)查看maven 版本
[root@jenkins ~]# mvn -version
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /usr/local/maven
Java version: 11.0.23, vendor: Oracle Corporation, runtime: /usr/local/java
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "6.8.7-1.el7.elrepo.x86_64", arch: "amd64", family: "unix"
(4)修改 maven 更新源
[root@jenkins ~]# vim /usr/local/maven/conf/settings.xml
#修改maven的仓库
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<mirrors>
备注:
阿里提供了 maven 更新源,可访问阿里官方网站査看详细信息。
https://maven.aliyun.com
7.为jenkins 安装 NodeJs
在对 Nodes 项目进行构建的时候,需要 g++的编译环境,不同的项目 Node]s 的版本也不一样,在进行部署的时候要根据项目的依赖版本进行选择。
[root@jenkins ~]# yum -y install gcc automake autoconf libtool make
[root@jenkins ~]# yum -y install gcc*
[root@jenkins ~]# tar zxvf node-v14.18.0-linux-x64.tar.gz
[root@jenkins ~]# mv node-v14.18.0-linux-x64 /usr/local/nodejs14
[root@jenkins ~]# ln -s /usr/local/nodejs14/bin/* /usr/local/bin/
四、Jenkins的安装与初始化设置
1.安装Jenkins
[root@jenkins ~]# cp jenkins.war /usr/local/tomcat/webapps
[root@jenkins ~]# cd /usr/local/tomcat/bin/
[root@jenkins bin]# sh startup.sh
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/local/java
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
[root@jenkins bin]# netstat -anpt | grep java
tcp6 0 0 :::8009 :::* LISTEN 6286/java
tcp6 0 0 :::8080 :::* LISTEN 6286/java
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 6286/java
将 jenkins.war 文件保存到Tomcat 服务的 /usr/local/tomcat/webapps 目录下。启动 Tomcat就会自动部署 Jenkins。
2.设置 jenkins 插件更新源
cd /root/.jenkins/updates
[root@jenkins updates]# sed -i 's/https:\/\/www.jenkins.io/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json
[root@jenkins updates]# sed -i 's/https:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json
注意:
default.json 文件需要 jenkins 初始化结束才能出来。此处需要稍等片刻。
[root@jenkins updates]# cat /root/.jenkins/secrets/initialAdminPassword
3. Jenkins 初始化
(1)登录Jenkins
访问网址:http://192.168.10.104:8080/jenkins
查看初始密码:
cat /root/.jenkins/secrets/initialAdminPassword
(2)选择插件安装方式
注意:
此处是在安装 Jenkins 过程中添加插件,也可以使用“选择插件安装”选项,跳过插件安装过程,等待 Jenkins 安装好后,登录到 Jenkins 再安装插件。
(3)创建管理员账号
本案例将初始的管理员账号和密码都设置为 admin
(4)结束安装
五、Jenkins 插件管理
1.修改 Jenkins 插件安装为国内源地址
在安装 Jenkins 时,选择默认安装插件会很慢,甚至会失败,因此安装时可以取消所有插件安装,跳过这一步,待 Jenkins 启动后,修改插件安装地址,安装插件。
(1)设置国内插件源
进入 Manage Jenkins->Plugins->Advanced settings 最下面有 Update site(升级站点),设置为如下链接,并点“提交”按钮。
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
(2)重启 Jenkins 服务
[root@jenkins ~]# /usr/local/tomcat/bin/shutdown.sh
[root@jenkins ~]# /usr/local/tomcat/bin/startup.sh
2.安装插件
点击“Manage jenkins”-->“Plugins”-->“Avalable plugins”,输入要安装的插件,并勾选列出来的插件,然后点安装。
在本课程内,可能会用的插件如下所示:
Git Parameter
Git Pipeline for Blue Ocean
GitLab
Blue Ocean
Blue Ocean Pipeline Editor
Blue Ocean core Js
Pipeline SCM API for Blue ocean
Dashboard for Blue Ocean
Build with Parameters
extended Choice ParameterKubernetes
Kubernetes CLI
Kubernetes credentials
Image Tag Parameter
Active choices
SSH
ansible
Maven IntegrationPublish over ssH
Role-based Authorization strategy
Nodejs
Git
Credentials
Credentials Binding
Dynamic Extended Choice Parameter Plug-InDynamic Parameter Plug-In
Pipeline
Pipeline:Declarative
Localization:Chinese(simplified)
注意:
红色的在初始化过程中已经安装上去的,此处可以不用再安装,如果在初始过程中没有安装,或安装不完全,此处可以都安装上去,为其他项目的实施提供可用功能。
提示:可以在此处做一个快照,方便后续实验
六、Jenkins 角色与权限管理
我们可以利用 Role-based Authorization strategy 插件来管理 Jenkins 用户权限,在前面的插件安装中已经安装过此插件。
1.开启权限全局安全配置
“Dashboard”-->“Manage Jenkins”-->“Security”-->“Authentication"
将授权策略修改为“Role-Based strategy”,并保存设置。
2.创建角色
为了更方便的为用户授权,jenkins 中使用角色作为一类权限的容器。角色是一组相关权限的集合。可以为用户指定角色,而不是直接指定权限。
(1)角色种类
Global roles:Global roles(全局角色):管理员等高级用户可以创建基于全局的角色
Item roles:针对某个或者某些项目的角色
Agent roles:节点相关的权限
(2)设置角色
“Dashboard”-->“Manage Jenkins”-->“Manage and Assing Roles”。点击“Manage Roles"
本案例中我们添加三个角色:
- baseRole:该角色为全局角色。这个角色需要绑定0verall 下面的 Read 权限,是为了给所有用户绑定最基本的 Jenkins 访问权限。注意:如果不给后续用户绑定这个角色,会报错误:用户名ismissing the overall/Read permission
- role1:该角色为项目角色。使用正则表达式绑定"my-item01.*",意思是只能操作名称为“my-item01”开头的项目。
- role2:该角色也为项目角色。绑定"my-item02.*",意思是只能操作“my-item02”开头的项目。
(3)添加 baseRole 角色到 Global roles
(4)添加role1和role2 角色到 Item roles
在“Role to add”中填写角色名称“role1”;“Pattern”中填写“my-item01.*”,表示 role1 的角色只能管理“my-item01.*”开头的项目添加好后点 Save 保存。
3.创建用户
(1)添加新用户
“Dashboard”-->“Manage Jenkins”-->“Users”,在右上角点击“create User”,创建用户。
(2)填写账号信息
(3)创建好后的效果
4.给用户分配角色
“Dashboard”-->“Manage Jenkins”-->“Manage and Assign Roles”,然后点击“Assign Roles”进入到分配角色的界面。
(1)为zhangsan用户绑定 baseRole 和role1 角色
在“Global roles”中点击“Add User”按钮,在弹框中输入用户 zhangsan,确定后勾选角色 baseRole:在“Item roles”中点击“Add User”按钮,在弹框中输入用户 zhangsan,确定后勾选角色 role1。
(2)为lisi 用户绑定 baseRole 和 role2 角色
用同样的方法为 1isi 设置角色。
在“Global roles”中点击“Add user”按钮,在弹框中输入用户 1isi,确定后勾选角色 baseRole:在“Item roles”中点击“Add user”按钮,在弹框中输入用户 lisi,确定后勾选角色 role2.设置好后,点击 save 保存。
5.创建项目测试权限
(1)创建项目
用管理员的权限创建两个项目,名字分别是 my-item01-zhangsan 和 my-item02-lisi
(2)分别用 zhangsan 和 lisi 的身份登录系统
可以发现,每个用户只能管理属于自己角色范围内的项目。
七、Jenkins 凭证管理
有许多第三方网站和应用程序可以与 Jenkins 进行交互,例如程序代码仓库,云存储系统和服务等
此类应用程序的系统管理员可以在应用程序中配置凭据以专供 Jenkins 使用。通常通过将访问控制应用于这些凭据来完成这项工作,以“锁定”Jenkins 可用的应用程序功能区域。一旦 Jenkins 管理员(即管理 Jenkins 站点的 Jenkins 用户)在 Jenkins 中添加/配置这些凭据,Pipeline 项目就可以使用凭据与这些第三方应用程序进行交互。
用管理员登录到 jenkins。
要在 Jenkins 使用凭证管理功能,需要安装 Credentials Binding插件,前面已经安装过此插件,这里不再安装。
凭据可以用来存储需要密文保护的数据库密码、Gitlab 密码信息、Docker 私有仓库密码等,以便Jenkins 可以和这些第三方的应用进行交互。
1.凭据的种类
jenkins 提供了多种类型的凭据,适应与不同的业务需求,具体类型如下:
- Username with password:用户名和密码
- GitHub App: GitHub 应用进行身份验证
- GitLab API token: 存储 Gitlab 的用户 API token
- OpenShift Username and password:存储 0penshift 的用户名和密码
- SSH Username with private key:使用 SSH 用户和密钥
- Secret file:需要保密的文本文件,使用时 Jenkins 会将文件复制到一个临时目录中,再将文件路径设置到一个变量中,等构建结束后,所复制的Secret file 就会被删除。
- Secret text:需要保存的一个加密的文本串,如钉钉机器人或 Github 的 api token
- Certificate:通过上传证书文件的方式
其中,常用的凭证类型有:Username with password(用户密码)和SSH Username with privatekey(SSH 密钥)。接下来以使用 Git 工具到 Gitlab 拉取项目源码为例,演示 Jenkins 的如何管理 Gitlab的凭证。
注意: 为了让 Jenkins 支持从 Gitlab 拉取源码,需要安装 Git 插件以及在 Centos7 系统上安装 Git工具。
2.凭据的作用范围
凭证具有与它们相关联的范围。这是一种表示它们如何才能被暴露的方式。Jenkins 使用的主要范围有如下 2种。
(1)system(系统)
顾名思义,这个范围与根上下文,也就是 enkins 系统相关联。此范围中的凭证只被暴露给系统和后台任务,并且一般被用于连接到构建节点或代理节点等。
(2)全局
全局范围是默认选项,通常用来确保 Jenkins 中的任务可以使用凭证。
3.添加用户密码类型的凭据
(1)添加凭据
“Manage jenkins”-->“credentials”,打开如下页面,并点击“System”,进入全局凭据管理界面,如下图所示。
在如下界面中,点击右上角的“Add credentials”按钮,添加凭据
(2)填写凭据参数
这里主要的内容有:
凭据类型:Username with password
范围:Global
用户名:root(该账号是 gitlab 中添加的账号)密码:gitlab 中为root 用户设置的密码(本案例此处为 pwd12345,注意不是系统的 root 密码)ID:选填(设置凭据的唯一标识,不设置会自行分配一个唯一标识)描述:选填(凭据名称,此处最好填写一下,使用凭据的时候便于识别,不设置就使用用户名)
点击 create 创建此凭据,添加结果如下:
(3)测试凭据
1)到 gitlab 中添加一个项目
登录到 gitlab,导入项目(本案例使用root 用户登录)。导入gitee 上的项目,访问级别使用私有类
型,链接如下:
https://gitee.com/kgc-wjq/league.git
2)复制出HTTP的仓库URL
http://192.168.10.105/root/league.githttp://192.168.10.105/root/league.git
3)创建测试项目 test01
创建一个 Freestyle 项目:新建 Item->Freestyle Project->确定
4)源码管理中设置仓库 URL 和凭据
在源码管理中点“Git”,代码仓库的 URL为 http://192.168.10.105/root/league.git
并选择 Gitlab 中 root 的凭据。最后保存设置。
5)测试代码拉取
点击 Build Now,立即构建此项目。可以在控制台输出査看构建日志。
6)查看拉取到 jenkins 主机中的代码
在 jenkins 主机的工作空间目录下,已经能够看到代码拉取到了 jenkins 主机本地。
[root@jenkins ~]# ls .jenkins/workspace/
test01 test01@tmp
4. 添加 SSH 类型的凭据
SSH类型的凭据可以使 Jenkins 在拉取 gitlab 中的代码时使用秘钥对的方式,不仅实现了免密连接。同时也会对数据进行加密,是一种安全可靠的凭据方式。
(1)在jenkins 主机上以 root 身份生成密钥对
(2)复制公钥
[root@jenkins ~]# cd .ssh/
[root@jenkins .ssh]# ls
id rsa id rsa.pub
其中 id rsa 为私钥文件,id rsa.pub 为公钥文件。
(3)将公钥存放到 gitlab
用 root 用户登录 gitlab,点击右上角的头像,在下拉菜单中点“preferences”,然后在左侧列表点击“SSH Keys”。
添加成功后的效果如下如图所示:
(4)在 jenkins 中添加 SSH 凭据
“Manage jenkins”-->“Credentials”,打开如下页面,并点击“System”,进入全局凭据管理界
(5)填写 SSH 凭据参数
这里主要的参数有:
类型:SSH
范围:Global
ID:可选
描述:可选
Username:root(这个秘钥对是用root 的身份生成的)Private Key:填写 root 生成的私钥。
(6)添加好的状态如下
(7)测试凭据
1)到 gitlab 中查看 SSH 的仓库链接,并复制下来
以 root 的身份登录到 gitlab,并复制出 SSH 的仓库 URL。
git@192.168.10.105:root/league.git
2)创建测试项目test02
3)在源码管理中设置 git 参数
将仓库的 ssh 链接粘贴到仓库 URL 处,并在下面选择 ssh 凭据。
4)构建项目测试
点击“Build New”,查看构建结果。
5)查看工作区域
[root@jenkins ~]# ls .jenkins/workspace/
test01 test01@tmp test02 test02@tmp
此处已经将 gitlab 中的项目拉取到了 Jenkins 本地。
上一篇: 爬虫小案例:爬豆网TOP250电影信息(包含面目全非的对象源代码,并进行详细教学)
下一篇: 1.如何租用服务器上的 GPU 来运行实验(以 AutoDL 为例) - 深度学习 - 研究实践 - 从 0 到 1
推荐阅读
-
了解 Jenkins 持续集成系统
-
入门 Jenkins 持续集成pipeline构建项目的简易指南
-
如何在实际项目中运用git-flow分支管理框架与Jenkins多分支持续集成流水线实践
-
SSM三大框架基础面试题-一、Spring篇 什么是Spring框架? Spring是一种轻量级框架,提高开发人员的开发效率以及系统的可维护性。 我们一般说的Spring框架就是Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是核心容器、数据访问/集成、Web、AOP(面向切面编程)、工具、消息和测试模块。比如Core Container中的Core组件是Spring所有组件的核心,Beans组件和Context组件是实现IOC和DI的基础,AOP组件用来实现面向切面编程。 Spring的6个特征: 核心技术:依赖注入(DI),AOP,事件(Events),资源,i18n,验证,数据绑定,类型转换,SpEL。 测试:模拟对象,TestContext框架,Spring MVC测试,WebTestClient。 数据访问:事务,DAO支持,JDBC,ORM,编组XML。 Web支持:Spring MVC和Spring WebFlux Web框架。 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。 语言:Kotlin,Groovy,动态语言。 列举一些重要的Spring模块? Spring Core:核心,可以说Spring其他所有的功能都依赖于该类库。主要提供IOC和DI功能。 Spring Aspects:该模块为与AspectJ的集成提供支持。 Spring AOP:提供面向切面的编程实现。 Spring JDBC:Java数据库连接。 Spring JMS:Java消息服务。 Spring ORM:用于支持Hibernate等ORM工具。 Spring Web:为创建Web应用程序提供支持。 Spring Test:提供了对JUnit和TestNG测试的支持。 谈谈自己对于Spring IOC和AOP的理解 IOC(Inversion Of Controll,控制反转)是一种设计思想: 在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC在其他语言中也有应用,并非Spring特有。IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。 将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。 Spring中的bean的作用域有哪些? 1.singleton:该bean实例为单例 2.prototype:每次请求都会创建一个新的bean实例(多例)。 3.request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 4.session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。 5.global-session:全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。 Spring中的单例bean的线程安全问题了解吗? 概念用于理解:大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。 有两种常见的解决方案(用于回答的点): 1.在bean对象中尽量避免定义可变的成员变量(不太现实)。 2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal(线程本地化对象)中(推荐的一种方式)。 ThreadLocal解决多线程变量共享问题(参考博客):https://segmentfault.com/a/1190000009236777 Spring中Bean的生命周期: 1.Bean容器找到配置文件中Spring Bean的定义。 2.Bean容器利用Java Reflection API创建一个Bean的实例。 3.如果涉及到一些属性值,利用set方法设置一些属性值。 4.如果Bean实现了BeanNameAware接口,调用setBeanName方法,传入Bean的名字。 5.如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader方法,传入ClassLoader对象的实例。 6.如果Bean实现了BeanFactoryAware接口,调用setBeanClassFacotory方法,传入ClassLoader对象的实例。 7.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。 8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执postProcessBeforeInitialization方法。 9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet方法。 10.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。 11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization方法。 12.当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy方法。 13.当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。 Spring框架中用到了哪些设计模式? 1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。 2.代理设计模式:Spring AOP功能的实现。 3.单例设计模式:Spring中的bean默认都是单例的。 4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。 5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。 7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。 还有很多。。。。。。。 @Component和@Bean的区别是什么 1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。 2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。 3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。 @Configuration public class AppConfig { @Bean public TransferService transferService { return new TransferServiceImpl; } } <beans> <bean id="transferService" class="com.kk.TransferServiceImpl"/> </beans> @Bean public OneService getService(status) { case (status) { when 1: return new serviceImpl1; when 2: return new serviceImpl2; when 3: return new serviceImpl3; } } 将一个类声明为Spring的bean的注解有哪些? 声明bean的注解: @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repository 在数据访问层使用(dao层) @Controller 在展现层使用,控制器的声明 注入bean的注解: @Autowired:由Spring提供 @Inject:由JSR-330提供 @Resource:由JSR-250提供 *扩:JSR 是 java 规范标准 Spring事务管理的方式有几种? 1.编程式事务:在代码中硬编码(不推荐使用)。 2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。 Spring事务中的隔离级别有哪几种? 在TransactionDefinition接口中定义了五个表示隔离级别的常量:ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 Spring事务中有哪几种事务传播行为? 在TransactionDefinition接口中定义了八个表示事务传播行为的常量。 支持当前事务的情况:PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。 不支持当前事务的情况:PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 其他情况:PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。 二、SpringMVC篇 什么是Spring MVC ?简单介绍下你对springMVC的理解? Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。 Spring MVC的工作原理了解嘛? image.png Springmvc的优点: (1)可以支持各种视图技术,而不仅仅局限于JSP; (2)与Spring框架集成(如IoC容器、AOP等); (3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。 (4) 支持各种请求资源的映射策略。 Spring MVC的主要组件? (1)前端控制器 DispatcherServlet(不需要程序员开发) 作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。 (2)处理器映射器HandlerMapping(不需要程序员开发) 作用:根据请求的URL来查找Handler (3)处理器适配器HandlerAdapter 注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。 (4)处理器Handler(需要程序员开发) (5)视图解析器 ViewResolver(不需要程序员开发) 作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view) (6)视图View(需要程序员开发jsp) View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等) springMVC和struts2的区别有哪些? (1)springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。 (2)springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。 (3)Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。 SpringMVC怎么样设定重定向和转发的? (1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4" (2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com" SpringMvc怎么和AJAX相互调用的? 通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象。具体步骤如下 : (1)加入Jackson.jar (2)在配置文件中配置json的映射 (3)在接受Ajax方法里面可以直接返回Object,List等,但方法前面要加上@ResponseBody注解。 如何解决POST请求中文乱码问题,GET的又如何处理呢? (1)解决post请求乱码问题: 在web.xml中配置一个CharacterEncodingFilter过滤器,设置成utf-8; <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> (2)get请求中文参数出现乱码解决方法有两个: ①修改tomcat配置文件添加编码与工程编码一致,如下: <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/> ②另外一种方法对参数进行重新编码: String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8") ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。 Spring MVC的异常处理 ? 统一异常处理: Spring MVC处理异常有3种方式: (1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; (2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器; (3)使用@ExceptionHandler注解实现异常处理; 统一异常处理的博客:https://blog.csdn.net/ctwy291314/article/details/81983103 SpringMVC的控制器是不是单例模式,如果是,有什么问题,怎么解决? 是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写成员变量。(此题目类似于上面Spring 中 第5题 有两种解决方案) SpringMVC常用的注解有哪些? @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代? 一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。 如果在拦截请求中,我想拦截get方式提交的方法,怎么配置? 可以在@RequestMapping注解里面加上method=RequestMethod.GET。 怎样在方法里面得到Request,或者Session? 直接在方法的形参中声明request,SpringMVC就自动把request对象传入。 如果想在拦截的方法里面得到从前台传入的参数,怎么得到? 直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象? 直接在方法中声明这个对象,SpringMVC就自动会把属性赋值到这个对象里面。 SpringMVC中函数的返回值是什么? 返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的。 SpringMVC用什么对象从后台向前台传递数据的? 通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以拿到数据。 怎么样把ModelMap里面的数据放入Session里面? 可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。 SpringMvc里面拦截器是怎么写的: 有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在SpringMvc的配置文件中配置拦截器即可: <!-- 配置SpringMvc的拦截器 --> <mvc:interceptors> <!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 --> <bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean> <!-- 只针对部分请求拦截 --> <mvc:interceptor> <mvc:mapping path="/modelMap.do" /> <bean class="com.zwp.action.MyHandlerInterceptorAdapter" /> </mvc:interceptor> </mvc:interceptors> 注解原理: 注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池 三、Mybatis篇 什么是MyBatis? MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。 讲下MyBatis的缓存 MyBatis的缓存分为一级缓存和二级缓存,一级缓存放在session里面,默认就有, 二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现Serializable序列化接口, 可在它的映射文件中配置<cache/> Mybatis是如何进行分页的?分页插件的原理是什么? 1)Mybatis使用RowBounds对象进行分页,也可以直接编写sql实现分页,也可以使用Mybatis的分页插件。 2)分页插件的原理:实现Mybatis提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql。 举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10 简述Mybatis的插件运行原理,以及如何编写一个插件? 1)Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、 Executor这4种接口的插件,Mybatis通过动态代理, 为需要拦截的接口生成代理对象以实现接口方法拦截功能, 每当执行这4种接口对象的方法时,就会进入拦截方法, 具体就是InvocationHandler的invoke方法,当然, 只会拦截那些你指定需要拦截的方法。 2)实现Mybatis的Interceptor接口并复写intercept方法, 然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可, 记住,别忘了在配置文件中配置你编写的插件。 Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不? 1)Mybatis动态sql可以让我们在Xml映射文件内, 以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。 2)Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。 3)其执行原理为,使用OGNL从sql参数对象中计算表达式的值, 根据表达式的值动态拼接sql,以此来完成动态sql的功能。 #{}和${}的区别是什么? 1)#{}是预编译处理,${}是字符串替换。 2)Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值(有效的防止SQL注入); 3)Mybatis在处理${}时,就是把${}替换成变量的值。 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里? Hibernate属于全自动ORM映射工具, 使用Hibernate查询关联对象或者关联集合对象时, 可以根据对象关系模型直接获取,所以它是全自动的。 而Mybatis在查询关联对象或关联集合对象时, 需要手动编写sql来完成,所以,称之为半自动ORM映射工具。 Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? 1)Mybatis仅支持association关联对象和collection关联集合对象的延迟加载, association指的就是一对一,collection指的就是一对多查询。 在Mybatis配置文件中, 可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 2)它的原理是,使用CGLIB创建目标对象的代理对象, 当调用目标方法时,进入拦截器方法, 比如调用a.getB.getName, 拦截器invoke方法发现a.getB是null值, 那么就会单独发送事先保存好的查询关联B对象的sql, 把B查询上来,然后调用a.setB(b), 于是a的对象b属性就有值了, 接着完成a.getB.getName方法的调用。 这就是延迟加载的基本原理。 MyBatis与Hibernate有哪些不同? 1)Mybatis和hibernate不同,它不完全是一个ORM框架, 因为MyBatis需要程序员自己编写Sql语句, 不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句, 并将java对象和sql语句映射生成最终执行的sql, 最后将sql执行的结果再映射生成java对象。 2)Mybatis学习门槛低,简单易学,程序员直接编写原生态sql, 可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发, 例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁, 一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性, 如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 3)Hibernate对象/关系映射能力强,数据库无关性好, 对于关系模型要求高的软件(例如需求固定的定制化软件) 如果用hibernate开发可以节省很多代码,提高效率。 但是Hibernate的缺点是学习门槛高,要精通门槛更高, 而且怎么设计O/R映射,在性能和对象模型之间如何权衡, 以及怎样用好Hibernate需要具有很强的经验和能力才行。 总之,按照用户的需求在有限的资源环境下只要能做出维护性、 扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 MyBatis的好处是什么? 1)MyBatis把sql语句从Java源程序中独立出来,放在单独的XML文件中编写, 给程序的维护带来了很大便利。 2)MyBatis封装了底层JDBC API的调用细节,并能自动将结果集转换成Java Bean对象, 大大简化了Java数据库编程的重复工作。 3)因为MyBatis需要程序员自己去编写sql语句, 程序员可以结合数据库自身的特点灵活控制sql语句, 因此能够实现比Hibernate等全自动orm框架更高的查询效率,能够完成复杂查询。 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系? Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。 在Xml映射文件中,<parameterMap>标签会被解析为ParameterMap对象, 其每个子元素会被解析为ParameterMapping对象。 <resultMap>标签会被解析为ResultMap对象, 其每个子元素会被解析为ResultMapping对象。 每一个<select>、<insert>、<update>、<delete> 标签均会被解析为MappedStatement对象, 标签内的sql会被解析为BoundSql对象。 什么是MyBatis的接口绑定,有什么好处? 接口映射就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置. 接口绑定有几种实现方式,分别是怎么实现的? 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加 上@Select@Update等注解里面包含Sql语句来绑定, 另外一种就是通过xml里面写SQL来绑定,在这种情况下, 要指定xml映射文件里面的namespace必须为接口的全路径名. 什么情况下用注解绑定,什么情况下用xml绑定? 当Sql语句比较简单时候,用注解绑定;当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多 MyBatis实现一对一有几种方式?具体怎么操作的? 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成; 嵌套查询是先查一个表,根据这个表里面的结果的外键id, 去再另外一个表里面查询数据,也是通过association配置, 但另外一个表的查询通过select属性配置。 Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别? 能,Mybatis不仅可以执行一对一、一对多的关联查询, 还可以执行多对一,多对多的关联查询,多对一查询, 其实就是一对一查询,只需要把selectOne修改为selectList即可; 多对多查询,其实就是一对多查询,只需要把selectOne修改为selectList即可。 关联对象查询,有两种实现方式,一种是单独发送一个sql去查询关联对象, 赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用join查询, 一部分列是A对象的属性值,另外一部分列是关联对象B的属性值, 好处是只发一个sql查询,就可以把主对象和其关联对象查出来。 MyBatis里面的动态Sql是怎么设定的?用什么语法? MyBatis里面的动态Sql一般是通过if节点来实现,通过OGNL语法来实现, 但是如果要写的完整,必须配合where,trim节点,where节点是判断包含节点有 内容就插入where,否则不插入,trim节点是用来判断如果动态语句是以and 或or 开始,那么会自动把这个and或者or取掉。 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? 第一种是使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列别名书写为对象属性名, 比如T_NAME AS NAME,对象属性名一般是name,小写, 但是列名不区分大小写,Mybatis会忽略列名大小写,
-
持续集成 03 - Jenkins 安装和配置
-
Jmeter+Ant+Git+Jenkins 持续集成简介
-
带你了解射频集成电路和系统设计第 3 期:射频双端口网络
-
什么是可用性测试?有效性(Effectiveness)-- 用户完成特定任务和实现特定目标的正确性和完整性程度;效率(Efficiency)-- 用户完成任务的正确性和完整性程度与所用资源(如时间)之比;满意度(Satisfaction)-- 用户在使用产品时的主观满意度和接受程度。 2.如何获得可用性? 可以参考以下原则:Gould、Boies 和 Lewis(1991 年)为以用户为中心的设计定义了 4 个重要原则: 早期以用户为中心:设计者应在设计过程的早期就努力了解用户的需求。 综合设计:设计的所有方面都应同步发展,而不是按顺序进行。使产品的内部设计始终与用户界面的需求保持一致。 早期和持续测试:当今唯一可行的软件测试方法是经验主义方法,即如果实际用户认为设计可行,该设计就是可行的。通过在整个开发过程中引入可用性测试,用户就有机会在产品推出之前对设计提出反馈意见。 迭代设计:大问题往往掩盖了小问题的存在。设计人员和开发人员应在整个测试过程中对设计进行迭代。 3...什么是可用性测试? 可用性测试是根据可用性标准对图形用户界面进行的系统评估。 可用性测试是衡量用户与系统(网站、软件应用程序、移动技术或任何用户操作设备)交互时的体验质量。4.如何进行可用性测试? l 实验室实验
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
docker jenkins 接口自动化测试持续集成实践