新兵训练营课程——环境与工具Java[转]
原文地址:http://weibo.com/p/1001643874239169320051
程序员在开发过程中会用到很多工具来提升开发和协作效率,这次介绍的是目前微博平台在开发过程中用到的一些工具,文章内容包括如何初始化开发环境,工具的基本使用和原理等。
这篇文章里会介绍到的一些工具:
-
打包构建:maven
-
版本管理:git
-
部署发布:docker
-
问题排查:wtool
开发环境的初始化
-
安装jdk1.7+,地址://java.com/zh_CN/download/faq/develop.xml
-
安装maven,地址:https://maven.apache.org
-
安装git,地址:https://git-scm.com
-
选择Eclipse或Idea作为编译器,并配置统一的代码格式化文件。
-
使用linux/mac的同学可以从内网仓库下载初始化脚本自动初始化开发环境,
-
使用linux/mac的同学可以安装wtool方便进行问题排查,地址:https://github.com/qdaxb/wtool
maven入门
简介
maven是什么
maven是一个项目构建和管理的工具,目前大部分java工程都选择使用maven作为构建工具。
是否还有其它构建工具
-
gradle目前正在开始流行的新一代构建工具,微博平台部分工程正在使用,可以参考 https://gradle.org
-
ant软件构建工具,过去几年已经逐渐被maven取代,参考:ant.apache.org
-
ant+ivy在ant的基础上提供依赖管理功能,参考://ant.apache.org/ivy/index.html
在这里还是以比较成熟的maven为例子,介绍一下构建管理工具的基本用途和使用方式。
maven能做什么
-
依赖管理
-
多模块构建
-
约定工程结构
-
约定构建模型
-
插件系统
maven的概念
maven pom
maven通过xml表示maven项目,一个项目所有的配置都放置在 POM.xml 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等。
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>weibo-demo</artifactId>
<groupId>com.weibo.api</groupId>
<version>1.0.21</version>
<packing>jar</packing>
</project>
-
maven使用groupId:artifactId:version三者来唯一标识一个唯一的二进制版本,可以缩写为GAV。
-
packaging代表打包方式,可选的值有:
-
-
pom, jar, war, ear, custom
-
Default is jar
-
pom的继承
<?xml version="1.0" encoding="UTF-8"?>
<project>
...
<parent>
<artifactId>weibo-api</artifactId>
<groupId>com.weibo.api</groupId>
<version>1.13</version>
</parent>
...
</project>
-
pom可以继承的元素如下:
-
-
groupId, version
-
Project Config
-
Dependencies
-
Plugin configuration
-
多模块工程
-
日常开发中一个工程可能比较庞大,这时可以把这个工程拆分成多个子模块来管理。一个多模块工程包含一个父pom,在其中定义了它的子模块;每个子模块都是一个独立的工程。
<project>
...
<packaging>pom</packaging>
<modules>
<module>maven-training</module>
<module>maven-training-web</module>
</modules>
</project>
多模块工程的文件夹结构如下:
Maven的约定
-
maven强调“约定优于配置”,具体来说,一个maven工程的约定有如下几个方面:
工程结构的约定
target: 构建输出目录
src: 源码目录
src/main: 源码主目录
src/test: 测试源码主目录
src/main/java: java源文件目录
src/main/webapp: web源码目录,如jsp等
src/main/resources: 不需要编译的文件
src/test/java: java测试源码目录
src/test/resources: 不需要编译的测试文件
构建生命周期的约定
generate-sources/generate-resources
compile
test
package
integration-test (pre and post)
Install
deploy
Maven常用命令
mvn clean
-清除clean
mvn clean compile
-执行 clean, generate*, compile
mvn clean package
-执行clean ,generate*, compile, test, interation-test, package
mvn install
-执行 generate*, compile, test, integration-test, package, install
mvn test
-执行 generate*, compile, test
Maven与依赖
-
如果当前工程依赖于其它的项目,那么可以在pom里声明如下:
<project>
...
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
-
scope分为: compile, test, provided (默认为compile)
-
type可以指定: jar, pom, war, ear, zip (默认jar)
依赖仲裁
当maven依赖的路径上出现冲突的时候可以用如下几种方式解决依赖冲突问题:
-
路径最短:依赖maven总是优先使用路径最短的依赖版本。
-
dependencyManagement:可以通过dependencyMangement指定依赖项目的版本号
-
父pom:子工程会继承父工程的依赖
-
强制指定依赖版本:使用[from,to]表示。如[1.0,1.1]代表从1.0到1.1版本;或者[1.0]代表强制使用1.0版本;[1.0,]代表1.0以上的版本;另外也可以用(),表示不包含边界值
解决冲突
-
查看依赖冲突的命令: $ mvn dependency:tree -Dverbose
-
$ mvn dependency:anaylyze
-
利用依赖仲裁机制解决冲突
-
-
通过dependencyManagement指定版本
-
通过parent指定版本
-
在本工程内声明依赖(路径最短)
-
强制指定版本
-
-
在依赖时指定Exclusions,排除有冲突的依赖
-
在依赖时增加Optional参数,所有依赖由最终打包的工程指定
内部仓库
-
内部工程的二进制包可以通过deploy命令发布到内部仓库,所有内部工程统一在内部仓库中管理。
总结
这一节介绍了maven的基本使用,包括pom的基本结构、如何执行构建、如何处理依赖冲突等。
todo
-
创建maven工程,GAV:
-
com.weibo.api:bootcamp_XXX:1.0.0-SNAPSHOT
-
bootcamp工程中包含两个java模块:bootcampapi、bootcampimpl,一个web模块:bootcamp_web
-
bootcamp项目依赖GAV:org.springframework:spring-context:4.2.0.RELEASE
-
bootcampimpl依赖bootcampapi
-
指定bootcamp_web中spring-context版本为3.2.14.RELEASE
-
执行一次打包
git与版本管理
为什么要有版本管理
版本控制(Version Control)的作用是追踪文件的变化。为什么需要版本控制?简单说,就是当你出错了,可以很容易地回到没出错时的状态。
git介绍
-
分布式版本管理系统:可离线使用
-
每个版本库的镜像都包含完整信息完整信息的概念
-
-
历史
-
分支
-
标记
-
let's go!
git一直被大家认为比较难以学习,很多公司也因为git的使用成本比较高所以一直还在用历史比较悠久的svn或其它版本管理工具,微博也花了一段时间由svn过度到git。
其实,只要理解了git的基本原理,配合实践,掌握日常使用的方法其实很简单。这里采用workshop的方式帮助大家理解,大家可以一边学习一边实践。
$ git help config
config 设置git变量
git config [--global] key value
> --global 全局变量
>> user.name 提交显示的用户名
>> user.email 提交显示的邮件
>> postBuffer 提交时的本地buffer大小
>> core.editor git默认编辑器
try it!
#edit global config
$ git config --global user.name qindi
$ git config --global user.email qindi@staff.sina.com.cn
$ git config --global postBuffer 50000000
$ git config --global core.editor vi
#check config value
$ mkdir work_repo
$ git init
# create empty git bare repository
$ cd ..
$ cd bare_repo
$ ls -la
# let's back to working repo
$ ls .git
status 显示git工作目录状态
try it!
#show status
$ echo 'hello world' >hello.txt
stage=暂存区,又称作index区使用git add命令会将文件增加到暂存区,此时文件内容被缓存,但是没有正式提交到版本库中,此时也没有建立版本号
git add [options] [--] [<pathspec>...]
$ git add hello.txt
# edit file after it is staged
$ echo 'hello2' >>hello.txt
# hello.txt is both in 'to be commit' and 'not staged'
# add the file into staged area again
$ git add .
如何忽略某些类型的文件:.gitignore
.settings/
.project
.classpath
bin/
commit 将暂存区提交到版本库
git commit [options]
> -a 提交所有更新过的文件(已在版本库的)
> -m 提交注释
> --amend 合并到上次提交
try it!
# commit the change
$ git status
# see the history
# edit the file again, commit it with -m and --amend option
$ echo 'hello3' >>hello.txt
$ git commit -m 'edit again' --amend
> --hard 重置staged,branch和working目录
reset命令指定文件路径的话,功能是把历史中版本中的某些文件恢复到暂存区,
如果没有指定文件路径,reset可以恢复分支指针、暂存区或工作区
$ echo 'reset' >>hello.txt
$ git status
#reset file in staged area,default to HEAD
$ git status
#reset branch,staged area and working directory
$ git status
# reset staged area to previous version
$ git status
# show the content in working directory
# show the content in git repository
$ git show HEAD:hello.txt
# ":" will show the content in staged area
如果命令中没有指定文件路径,则在取出文件的同时还回修改head指针,
$ git reset --hard HEAD
# update staged area
$ git add -u
# update working directory
$ echo 'checkout2' >>hello.txt
$ git status
# checkout default replace working directory with staged area
$ git status
$ echo 'checkout2' >>hello.txt
# checkout with commit will replace both working directory and staged area
$ git status
git rm [options] [--] [<pathspec>...]
# add a new file to staged area
$ echo 'rm' >rm.txt
$ git status
# remove it from staged area
$ git status
# remove the file
$ git rm hello.txt
$ git commit
刚才说的都是在本地仓库进行提交和恢复的路径图,初次接触git的同学可能看的有点晕,可以对照下面的图理解一下:
这是checkout的第三个功能,当checkout后面跟的参数是分支名时,会进行分支切换,
$ git reset --hard HEAD
# show branchs in git repository
$ git checkout -b branch1
# show branchs again
$ echo 'branch1' >> hello.txt
$ git commit -am 'test branch1'
$ git log
# switch to master again
$ git log
merge 合并分支
git merge [options] [<branch>]
> --no-ff 不使用fast-forward模式
> --abort 取消当前合并
merge做了什么(1)
如果当前提交是另一个分支的祖父节点,就导致fast-forward合并。指向只是简单的移动,并生成一个新的提交。
merge做了什么(2)
如果当前节点与合并节点不是祖先关系,就将当前节点、被合并的节点与他们的共同祖先进行一次三路合并,结果先保存到当前目录和索引,然后做一次新提交。
merge时冲突了怎么办
> * 解决冲突
> 1 修改文件,解决冲突
> 2 把文件添加到stage区
> 3 commit
> * 放弃合并
> git merge --abort
try it!
# create new branch branch2, do some update
$ echo 'merge1' >>hello.txt
$ git commit -am 'edit branch2'
# switch to master, merge will in fast-forward mode
$ git checkout master
$ git log
# drop this merge, do it again with no-ff param
$ git merge branch2 --no-ff
# let's make some confict
$ echo 'merge confict master' >>hello.txt
$ git commit -am 'edit master for confict'
$ echo 'merge confict branch2' >>hello.txt
$ git commit -am 'edit branch2 for confict'
$ git merge master
branch 管理分支
git branch [options] [<branch>]
> 无参数 显示所有本地分支
> -d/D 删除分支/强制删除分支
> -m/M 重命名分支/强制重命名分支
try it!
# show all local branch
$ git branch -m branch2 branch2a
# remove branch2a
$ git tag
# make a tag
$ git tag
# delete tag
$ git tag
版本库同步命令
git与其他版本管理工具一个比较大的区别就是
clone 克隆版本库
git clone url-to-repository
remote 管理远程仓库
git remote command <name>
> add
> set-url
> remove
> rename
try it!
$ git remote add origin ~/git_workshop/bare_repo
$ git remote show origin
push 把本地分支推送到远程
git push [options] [<repository> [<refspec>...]]
> --all 所有分支
> --tags 推送tag
> --prune 删除本地不存在的远程分支
> -f 覆盖远程仓库
> -u 建立本地与远程分支的关联
try it!
# push local master to remote master
$ git push origin master:master
# local branch is not tracked, push will not work
# push with -u will set upstream for local branch
$ git push -u origin master
# -vv shows remote track branch
$ git branch -vv
# push local branch1 to remote branch branch2
$ git push origin branch1:branch2
$ git branch -avv
# branch -u could also set upstream
$ git branch -u origin/branch2
# --all will push all branchs to remote repository
$ git push --all -u
$ git branch -avv # -a shows remote branchs
# push empty branch will delete remote branch
$ git push origin :branch2
$ git branch -avv
fetch 把远程仓库同步到本地
git fetch [options] [<repository> ]
pull 把远程仓库同步到本地,并更新本地分支
git pull [options] [<repository> [<refspec>...]]
> --rebase 使用rebase方式合并远程更新
> --prune 删除本地镜像中的过期分支
> -f 覆盖本地分支
实践与tips
为什么我用git的时候XXX不了?
-
看错误说明!
-
git status
-
git help
我的本地分支提交好像有问题!
-
git checkout -b branch_bak
-
随便搞
我的本地库好像被我搞乱了!
-
cp localRepo localRepo_bak
-
随便搞
团队的远程库好像被我搞乱了!
-
git clone //path_to_repo repo_bak
-
与所有团队成员同步状况,解决问题之前不要pull或push
-
临时分支异常:建立新分支,利用merge、rebase或cherry-pick更新分支,删除异常分支
-
永久分支异常:联系git工程管理员或gitlab管理员修复问题,之后做深刻的自我反省