Maven

Maven是一个基于java平台的自动化构建工具(编译-测试-打包-部署->自动构建),也是项目管理工具。
Maven的设计核心是约定优于配置(convention over configuration),也称作按约定编程,是一种软件设计范式。

主流的项目构建工具有:Ant、Maven、Gradle等。
Apache Maven是一个软件项目管理工具,基于POM(项目对象模型)的概念,管理项目的依赖、编译、文档等信息。
使用Maven管理项目时,项目依赖的jar包不必存在于工程内,而是集中放置在用户目录中的.m2目录中。
Ant是命令式,Maven是声明式。Ant需要指明各种动作,以及执行这些动作的顺序。Maven则默认大家都知道有各种动作,都遵守一个良好的目录结构,一个通用的构建过程。因此使用Maven时我们只需要告诉Maven希望构建什么,不需要告诉它如何构建。因为Maven已经在构建生命周期、阶段和目标中定义好了。我们要做的就是编写声明式的pom.xml文件。
Gradle结合以上两个的优点,继承了Ant的灵活和Maven的生命周期管理,它被google作为了Android御用管理工具。它不用XML作为配置文件格式,采用了DSL格式,使得脚本更加简洁。Gradle引入了基于Groovy语言的DSL语法来代替XML配置,因此它的配置文件是一个Groovy文件。Gradle还把Maven的设计核心(Convention Over Configuration)发扬光大,而Gradle的配置即代码又超越了Maven.在Gradle中任何配置都可以作为代码被执行的,我们也可以随时使用已有的Ant脚本,Java类库,Groovy类库来辅助完成构建任务的编写。

Apache Maven最初用于替代Apache Ant。相比Ant的指令方式,Maven采用了不同方式对项目进行构建进行抽象,比如约定源码、资源、目标文件的位置。
Maven的约定目录结构:
I.main->执行项目,test->测试项目,两个目录下都有java和resources(java:java代码,resources:资源代码/配置代码)。
II.target:用于存放编译、打包后的输出文件。
III.pom.xml:项目对象模型。
域名反转.大项目名
子模块名
版本号

Maven中央仓库信息速查

http://mvnrepository.com/
http://maven.outofmemory.cn/

maven plugin中的概念

lifecycle:总任务,它是一系列的phase组成,它运行完后就得到了一个结果,中间的过程是phase完成的。
常见的lifecycle有 | clean | package ear | pageage jar | package war | site等等

phase:阶段任务,一个lifecycle可以包含任意个phase,phase的执行是按顺序的,一个phase至少绑定很一个goal,没有goal的phase是没有意义的。
常见的phase有package,install,deploy。

goal: 执行任务的最小单元,它可以绑定到任意个phase中,一个phase有一个或多个goal,goal也是按顺序执行的,一个phase被执行时,绑定到phase里的goal会按绑定的时间被顺序执行。

mojo: lifecycle与phase与goal都是概念,mojo才是做具体事情的,可以简单理解mojo为goal的实现类。

Maven的插件机制是完全依赖Maven的生命周期的,因此要先理解Maven生命周期。

Maven生命周期

Maven有三套生命周期,它们相互独立、负责软件工程的不同方面的工作。这三套生命周期分别是:

  • Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle 构建的核心部分,编译,测试,打包,部署等。
  • Site Lifecycle 生成项目报告,站点,发布站点。

它们是相互独立的,可以仅调用clean来清理工作目录,调用site来生成站点。也可以直接运行mvn clean install site运行全部三套生命周期。

每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。
例如运行mvn clean,这个的clean是Clean生命周期的一个阶段。Clean生命周期一共包含了三个阶段:

  • pre-clean 执行一些需要在clean之前完成的工作
  • clean 移除所有上一次构建生成的文件
  • post-clean 执行一些需要在clean之后立刻完成的工作

mvn clean中的clean就是上面的clean阶段,在一个生命周期中运行某个阶段的时候,它之前的所有阶段都会被运行,即mvn clean等同于mvn pre-clean clean,mvn post-clean 等同于 pre-clean clean post-clean。这是Maven很重要的一个规则,可以简化命令行的输入。

打包

使用mvn package进行编译打包时,Maven会执行src/test/java中的JUnit测试用例,使用参数-DskipTests和-Dmaven.test.skip=true可以跳过测试,这两个参数的主要区别是:
-DskipTests,不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
-Dmaven.test.skip=true,不执行测试用例,也不编译测试用例类。

安装jar到本地Maven库

把生成的Jar文件放入本地库,以让其他项目使用。 /.m2/repository目录是Maven本地库的默认位置。
在项目目录下执行: mvn install
成功后输出:
[INFO] Installing /Users/hycx/i_workspace/yirui/yirui-common/target/yirui-common-1.0-SNAPSHOT.jar to /Users/hycx/.m2/repository/com/yirui/yirui-common/1.0-SNAPSHOT/yirui-common-1.0-SNAPSHOT.jar
[INFO] Installing /Users/hycx/i_workspace/yirui/yirui-common/pom.xml to /Users/hycx/.m2/repository/com/yirui/yirui-common/1.0-SNAPSHOT/yirui-common-1.0-SNAPSHOT.pom
[INFO] BUILD SUCCESS

mvn deploy:另外还可以把生成的jar放到远程仓库,例如可以用Sonatype创建一个私有的服务存放私有的jar。

打包时加入本地库

spring boot工程中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>

<dependencies>
<!--local jar-->
<dependency>
<groupId>0</groupId>
<artifactId>0</artifactId>
<version>0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/CCP_REST_SMS_SDK_JAVA_v2.6.3r.jar</systemPath>
</dependency>
</dependencies>

<!--springboot-1.5.x对应的springcloud的版本需要使用Camden.SR6-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--指定includeSystemScope为true,打包本地库-->
<configuration><includeSystemScope>true</includeSystemScope></configuration>
</plugin>
</plugins>
</build>
</project>

添加源代码目录

<build>
    <plugins>
        <!-- add generated proto buffer classes into the package -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>1.8</version>
            <executions>
                <execution>
                    <id>add-source</id>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>add-source</goal>
                    </goals>
                    <configuration>
                        <sources>
                            <source>${project.basedir}/../yirui-savenergy-common/src/main/java</source>
                        </sources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Maven中模块间的关系

3种关系:继承、依赖、聚合。
继承是指子项目继承了父项目的Pom。
依赖即导入组合。
聚合是指一个聚合工程(aggregator),它也是Maven Project,其pom文件中打包方式(packaging)为pom。并且它引入了新的元素:modules—module,用来包含了多个子模块,每个子模块也是一个Maven Project。其pom内容示例如下:

<?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.yirui.common</groupId>
    <artifactId>yirui-modules</artifactId>
    <version>1.0-SNAPSHOT</version><!--版本:聚合模块的版本和被聚合模块版本一致,如果被子模块继承,
这里就是唯一指定版本的地方-->
    <packaging>pom</packaging>
    <modules>
        <module>yirui-common</module>
        <module>yirui-common-database</module>
        <module>yirui-common-message</module>
        <module>yirui-common-security</module>
        <module>yirui-common-sms</module>
    </modules>

</project>

https://blog.csdn.net/wanghantong/article/details/36427411

在一些最佳实践中我们发现:一个POM可以既是聚合POM,又是父POM,这么做主要是为了方便。

pom文件配置

modelVersion: 表示pom文件的Maven版本。
dependency下scope:表示此类库在项目中的作用阶段范围,默认为compile,表示在编译和打包时都需要此类库。阶段分为编译、单元测试、打包、运行。scope 可选择项有compile、provided、runtime、test。
build:build下可以包含plugins,这些插件可以修改项目的构建方式。例如编译的java版本。

dependencyManagement与dependencies

dependencyManagement的特性:在dependencyManagement中配置的元素既不会给parent引入依赖,也不会给它的子模块引入依赖,仅仅是它的配置是可继承的。
dependencyManagement 元素用在父项目的POM文件中,用来统一模块间的依赖版本问题。子项目中可以引用一个依赖而不显示地指明版本号,Maven会沿着父子层次向上查找一个拥有dependencyManagement元素的项目,找到后使用在dependencyManagement元素中指定的版本号。
dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。
父项目中的dependencies被子项目全部继承。如果依赖只在某个子项目中使用,则可以只在子项目的pom.xml中引入,防止父pom的过于臃肿。

类似地,dependencyManagement 元素是用来管理插件的。

配置settings.xml

在Maven中提供了一个settings.xml文件来定义Maven的全局环境信息。这个文件会存在于Maven的安装目录的conf子目录下面,或者是用户家目录的.m2子目录下面。
根标签settings标签中的元素:

  • servers 下面可以定义一系列的server子元素,表示连接远程服务器的验证方式。主要有username/password和privateKey/passphrase这两种方式。
    <servers>
    <server>
    <id>id</id>
    <username>用户名</username>
    <password>密码</password>
    </server>
    </servers>
    
  • mirrors 用于定义一系列的远程仓库的镜像。
    mirrors中可以配置多个mirror,maven的mirror是镜像,而不是“分库”,只有当前一个mirror无法连接的时候,才会去找后一个,类似于备份和容灾。多个mirror,maven会根据id的字母排序来指定第一个,所以不管怎么排列,一定会找到A这个mirror来进行查找,当A无法连接,出现意外的情况下,才会去B查询。id:是用来区别mirror的,所有的mirror不能有相同的id。
    mirrorOf:用来表示该mirror是关联的哪一个仓库,其值为其关联仓库的id。当要同时关联多个仓库时,这多个仓库之间可以用逗号隔开;当要关联所有的仓库时,可以使用“*”表示;当要关联除某一个仓库以外的其他所有仓库时,可以表示为“*,!repositoryId”;当要关联不是localhost或用file请求的仓库时,可以表示为“external:*”。
    url:表示该镜像的url。当Maven在建立系统的时候就会使用这个url来连接远程仓库。central是官网仓库的id,如果存在多个mirror,一定要把mirrorOf *(星号)的放到最下面。

maven仓库搜索顺序

build一个Maven项目的时候,Maven会检查pom.xml文件中项目的依赖,然后按以下顺序依次搜索依赖,直到找到:
1)搜索本地仓库
2)搜索中央仓库
http://repo1.maven.org/maven/是旧仓库,有时会从这里下载。
https://repo.maven.apache.org/maven2是新的仓库。
3)pom.xml里声明的私有远程仓库

关于maven配置文件setting.xml中的配置
https://blog.csdn.net/TheManOfCoding/article/details/78864965
https://blog.csdn.net/cwh056056/article/details/49646111

-source 1.5 中不支持方法引用

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Maven打包

在/tests下自定义settings.xml文件,然后启动docker容器:
docker run –name maven1 -v /tests:/root/.m2 -it maven /bin/bash
进入后在项目目录中运行 mvn package 打包。

https://hub.docker.com/r/library/maven/

常用Maven Plugin,插件介绍
https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html

Git

Git简介

Subversion、CVS等属于集中式版本控制系统,只有一个仓库(repository)存在于服务器中,有多个工作目录(working copy)。
Git是分布式版本控制系统,除了服务器中的仓库,每一个工作目录中还都包含一个完整仓库,这样可以支持离线工作,即可以先提交到本地仓库,稍后再提交到服务器仓库。
分布式系统理论上比集中式的单服务器系统更健壮,单仓库系统一旦服务器出现问题整个系统就不能运行了,分布式系统通常不会因为一两个节点而受到影响。

git – 简明指南

http://rogerdudler.github.io/git-guide/index.zh.html

本地仓库由3部分组成:工作目录(stage),缓存区(index),head
提交的过程:暂存->commit->push
commit命令是提交到HEAD,push命令是提交到远端仓库
git pull origin master是把远端origin版本库改动更新到本地master分支上。
git push origin master是把本地master分支改动推送到远端origin版本库上。

clone代码到本地

#会在当前目录下创建以工程名称命名的目录
git clone https://git.oschina.net/
xxxx.git

git报错:github fail to sync branch

启动shell

git fetch https://github.com/abc/abc.git
git reset --hard origin/master

http://scribu.net/blog/resetting-your-github-fork.html

撤消对文件的修改 git checkout — <file>

git checkout -- Project1/BPushConfig.plist

http://blog.csdn.net/wirelessqa/article/details/20152353

清空暂存区

撤销已暂存的文件

git reset head 
git reset head 文件名

撤销已提交到本地的文件

git reset head^

查看帮助

git reset -help

git reset [–hard|soft|mixed|merge|keep] [或HEAD],将当前的分支重设(reset)到指定的或者HEAD(如果不显示指定commit,默认是HEAD,即最新的一次提交),并且根据[mode]有可能更新index和working directory。mode的取值可以是hard、soft、mixed、merged、keep。

fatal: The remote end hung up unexpectedly

解决fatal: The remote end hung up unexpectedly,执行下方面的命令,把可提交的内容设置大一些。

git config http.postBuffer 524288000

使用sshkey免登录

在gitoschina中使用sshkey,把.pub的内容复制到公钥框内确定保存即可,就可以在本地免登录更新了。
http://git.oschina.net/profile/sshkeys

删除已经提交到远程仓库的目录

git rm -r --cached target
git commit -m "delete target/"
git push origin master

http://blog.csdn.net/qq_21544879/article/details/51306746

添加被忽略的文件到git

git add -f libWeiboSDK.a 

GitLab

GitLab是利用 Ruby on Rails 一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

SVN

svn 常用命令

svn update 简写:svn up
svn update 如果后面没有目录,将当前目录以及子目录下的所有文件都更新到库最新版本。
svn update -r 12679 test.php 将版本库中的文件test.php还原到版本12679
svn update test.php 将版本库更新到本地。

如果在提交的时候提示过期,是因为冲突,需要先update,修改文件,然后清除svn resolved,最后再提交commit。
嵌出指定版本的工程

svn checkout 工程http地址 -r 版本号
例:svn checkout http://…/project1 -r 8321
http://os.51cto.com/art/200908/143157.htm

svn 导入

例如:将本地目录local1导入到版本库的trunk/server1,trunk/server1在导入之前不需要存在,svn import会递归的创建目录。
在终端中进入local1同级目录,然后执行以下代码
svn import -m “New import” local1 http://…/trunk/server1
这样会把local1目录下的文件导入到/trunk/server1下,不会创建local1目录。
在导入数据之后,本地的local1目录并没有纳入版本控制,为了开始工作,要运行svn checkout得到一个干净的目录树工作拷贝。
svn import -m “import libs” libs https://xxx.googlecode.com/svn/trunk/xxx/KxxxX/libs
svn import -m “import” controller https://xxx.googlecode.com/svn/trunk/re…../controller/

@的问题:

在iOS开发中,遇到Default@2x.png文件名不被svn命令完全识别的问题。
解决方法是在这个特殊文件名后面再加一个@,例如
svn add Default@2x.png@
svn remove Default@2x.png@

revert

svn revert --depth=files path/to/directory
 svn revert 目录 -R

查看某版本修改过的文件列表

svn log -r版本号 -v

查看查文件的历史版本

svn log 本地文件路径

查看svn库信息,包括服务器路径等

svn info

列出自某版本或某日期以来修改过的文件

svn diff -r 1038 --summarize svn://path > changedfiles.txt
svn diff -r 1038:HEAD --summarize svn://path > changedfiles.txt
svn diff -r {2015-05-06} --summarize https://path > changedfiles.txt
svn diff -r {2015-05-04}:{2015-05-05} --summarize https://path > changedfiles.txt

软件版本

一般项目版本分三段:主、次、修订。
SNAPSHOT表示开发中的版本
RELEASE表示正式发布版本
RC:release candidate 发布候选版本
GA:general avaliability 基本可用版本
NG:next generation
M:MileStone 里程碑
TM:Trade Mark 注册商标,带上TM同时起到了强调这个已是注册商标的作用。

周期顺序:
SNAPSHOT->ml->m2…->RC->GA->RELEASE

Sonatype Nexus3

sonatype/nexus3

Sonatype Nexus Repository ManagerOSS 3.12.1-01,OSS:对象存储服务。
Maven项目默认都是直接使用Maven提供的Central Repository,还可以创建一个私有的Repository(Internal Repository),所有项目都只和这个专属的Repository打交道,包括下载依赖,部署等,专属Repository有以下好处:
代理外部Repository(比如Maven Central Repository),可以对外部Repository做各种各样的过滤操作,比如可以限制只使用Spring的某个版本。
通过代理,专属Repository还可以起到缓存的作用,这样公司的每个开发者只需要从局域网的专属Repository下载依赖,而不用消耗对外网络资源。
发布公司自己的项目,如果开发的项目需要被公司的其他团队使用,而又不能发布到公司外部的Repository中,那么专属Repository是正中下怀的选择。
发布一些购买的第三方软件产品以供公司所有人使用,比如Oracle的数据库Driver。
存在多种专属Repository,比如NexusArtifactory等,甚至可以用一个FTP服务器作为一个专属Repository。下面通过docker启动一个nexus私有仓库:
持久目录 needs to be writable by the Nexus process, which runs as UID 200。启动完成后,在浏览器中访问 http://ip:8081/。

$ mkdir /alidata/docker_work/maven/repository && chown -R 200 /alidata/docker_work/maven/repository
$ docker run -d -p 8081:8081 --name nexus1 -v /alidata/docker_work/maven/repository:/nexus-data sonatype/nexus3

参考
https://hub.docker.com/r/sonatype/nexus3/#running
https://blog.csdn.net/wanghuan1191/article/details/79104303
https://www.cnblogs.com/helong/articles/2254446.html
Nexus Repository 3的性质
https://blog.csdn.net/liumiaocn/article/details/62050525
sonatype Nexus3 用户操作界面和设置
https://www.jianshu.com/p/6139ede291d2
maven的setting配置文件中mirror和repository的区别
https://www.jianshu.com/p/274c363ffd7c

在模块pom中指明要部署到的目的Repository

配置snapshot和release两种发布版本对应的Repository:
<distributionManagement>
<repository>
<id>nexus</id>
<name>Internal Release Repository</name>
<url>http://ip:8081/repository/maven-releases</url>
</repository>
<snapshotRepository>
<id>nexus</id>
<name>Internal Snapshot Repository</name>
<url>http://ip:8081/repository/maven-snapshots</url>
</snapshotRepository>
</distributionManagement>

nexus中会为同一个版本的每次deploy生成一个时间戳,业务端去仓库下载时会下载到最后的一次提交。

直接在pom中设置仓库

在业务项目中配置一个远程仓库。
<repositories>
<repository>
<id>nexus1</id>
<name>nexus1</name>
<layout>default</layout>
<!– 此为仓库地址,应用 group 类型可以相当于同时添加多个仓库地址 –>
<url>http://ip:8081/repository/maven-snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

在.m2/settings.xml中设置远程仓库

在settings.xml中设置的远程仓库会被所有项目使用。如果此远程仓库不能连接访问,在maven构建时会到中央仓库去查找。
<profiles>
<profile>
<id>NexusRepo</id>
<repositories>
<repository>
<id>nexus</id>
<name>Nexus3 Repository</name>
<url>http://xxxx:8081/repository/maven-snapshots/</url>
<releases>
<enabled>true</enabled>
</releases>
<!– snapshots默认是关闭的,需要手动开启 –>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
<!– 只有激活后才生效,此代码为激活代码 –>
<activeProfiles>
<activeProfile>NexusRepo</activeProfile>
</activeProfiles>

在.m2/settings.xml中设置仓库的镜像

mirrorOf中的仓库被访问时会自动找镜像,如果此镜像无法访问就不会再去中央工厂。
镜像对应的仓库不必在repositories中配置。

<mirror>
<id>nexusMirror</id>
<!– *号代表所有仓库,central代表中中央仓库,此处也可以单独设置,以逗号隔开 –>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<!–这个url从仓库列表中maven-central行中拷贝–>
<url>http:// xxxx:8081/repository/maven-central/</url>
</mirror>