Maven学习笔记

来源:互联网 发布:怎么开淘宝网店及货源 编辑:程序博客网 时间:2024/05/17 21:52
Maven:构建工具、依赖管理工具、项目信息管理工具

maven的安装与配置先安装配置JDK》然后安装配置Maven


"D:\JavaDeveloper\apache-maven-3.3.9\conf\settings.xml" 配置文件解析:
<settings>:maven全局配置settings.xml文档的根元素
<localRepository>:本地仓库存放位置,默认值${user.home}/.m2/repository
<interactiveMode>:maven是否与用户交互,默认值true
<offline>:离线模式,默认值false,如果不想每次编译,都去查找远程中心库,那就设置为true。当然前提是你已经下载了必须的依赖包。
<pluginGroups> <pluginGroup>:插件组
<proxies> <proxy> :代理,主要用于无法直接访问中心的库用户配置
<servers> <server> :下载与部署仓库的认证信息,与POM中的 distributionManagement相关
<mirrors> <mirror> :仓库镜像
<profiles> <profile> :
<activeProfiles> <activeProfile>:激活profile



POM:Project Object Model 项目对象模型 (pom.xml是Maven项目的核心,定义了项目的基本信息,描述了项目如何构建,声明了项目依赖等)

maven项目结构:

CarOrderAdmin:src/main/java:存放项目CarOrderAdmin的主代码
CarOrderAdmin:src/main/resources:存放项目CarOrderAdmin的资源文件
CarOrderAdmin:src/test/java:默认的测试代码目录
CarOrderAdmin:src/test/resources:用于测试的资源文件

CarOrderAdmin:target:输出目录,默认maven项目构建的所有输出都在target/目录中,项目主代码将编译至target/classes目录

Archetype:原型、模板
maven-archetype-quickstart



pom.xml文件解析:
<project>:pom文件的根元素。
<modelVersion>4.0.0</modelVersion>:指定当前pom模型的版本,对于maven3来说只能是4.0.0。
<groupId>:定义当前maven项目隶属的实际项目,一般是域名倒写+实际项目名,如现在的用车实际项目car,对应的groupId就应该是com.ly.car,虽然可以乱写,但是最好遵守规则,除非哪天你发明了更好的规则。(maven项目和实际项目不是一对一的关系,由于模块化的思想,一个实际项目会被划分成很多模块,即maven项目)
<artifactId>:定义实际项目中的一个maven项目(即模块),推荐使用实际项目名称作为artifactId的前缀。如spring项目的模块spring-core:<artifactId>spring-core</artifactId>。
<version>:定义当前maven项目的版本,如0.0.1-SNAPSHOT,SNAPSHOT是快照的意思,意味着该项目还处于开发中,不是稳定的版本。
<packaging>:定义maven项目的打包方式,不定义该元素时默认是jar。(可选的)
<classifier>:帮助定义构建输出的一些附属构件,附属构件与主构件对应,如主构件:spring-core-4.2.6.RELEASE.jar,附属构件:spring-core-4.2.6.RELEASE-javadoc.jar、spring-core-4.2.6.RELEASE-sources.jar。(不能直接定义)
<name>:一个对用户友好的项目名称,非必须但推荐。
<description>:项目的描述信息。

groupId+artifactId+version+packaging:定义一个项目的坐标,构件名一般规则:artifactId-version.packaging

依赖的配置:
<project>
……
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
<optional>false</optional>
<exclusions>
<exclusion>

</exclusion>
</exclusions>
</dependency>
</dependencies>
……
</project>


<scope>XXX</scope>:依赖范围,用来控制依赖与三种classpath(编译classpath、测试classpath、运行classpath)的关系,
compile:默认值,使用此依赖范围的maven依赖,对于编译、测试、运行三种classpath均有效。如spring-core,在编译、测试、运行时都需要使用到该依赖。
test:使用此依赖范围的maven依赖,只对测试classpath有效,如JUnit。
provided:使用此依赖范围的maven依赖,只对编译、测试classpath有效。如servlet-api,编译和测试项目时需要使用该依赖,但在运行时,由于web容器已提供,就不需要再引入该依赖了。否则容易造成版本冲突。
runtime:使用此依赖范围的maven依赖,只对测试、运行classpath有效。如JDBC的具体驱动mysql,因为编译时只需要JDK自带的JDBC接口,只有在测试或运行时才需要JDBC的具体实现驱动。
system:和provided依赖范围一致,但是需要通过<systemPath>显示指定本地的依赖文件的路径,由于该依赖与本机系统绑定了,可能造成构建的不可移植,应谨慎使用,如:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
<scope>system</scope>
<systemPath>d:/alibaba/fastjson.3.0.5.jar</systemPath>
</dependency>

传递性依赖:如项目com.ly.car:CarOrderBase直接依赖于org.springframework:spring-core,而spring-core又有其自己的依赖commons-logging,但是我们不需要自己手动添加间接依赖,maven会解析各个直接依赖的pom,将那些必须的间接依赖引入进来。
依赖调解:A>B>C>X(1.0) A>D>X(2.0) 依赖冲突,maven会按其自己的规则(路径最近者、第一声明者)选择一个依赖X(2.0)。
可选依赖:<optional>true</optional>,一般不要使用。
排除依赖:A>B>C(snapshot),构件C不稳定会影响到当前项目,需要排除,使用如下:
<exclusions>
<exclusion>
<groupId>com.XXX</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>

归类依赖:多个依赖来自同一个项目的不同模块,他们的版本相同,因此使用<properties>来定义maven属性
<properties>
<spring.version>4.0.8.RELEASE</spring.version>
</properties>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>

优化依赖:去除多余的依赖,显示声明某些必要的依赖。

仓库的布局
路径与坐标的大致对应关系为groupId/artifactId/version/artifactId-version.packaging
groupId中的句点分隔符转换成路径分隔符
Maven处理仓库的java源码:
    private static final char PATH_SEPARATOR = '/';    private static final char GROUP_SEPARATOR = '.';    private static final char ARTIFACT_SEPARATOR = '-';    public String pathOf( Artifact artifact )    {        ArtifactHandler artifactHandler = artifact.getArtifactHandler();        StringBuilder path = new StringBuilder( 128 );        path.append( formatAsDirectory( artifact.getGroupId() ) ).append( PATH_SEPARATOR );        path.append( artifact.getArtifactId() ).append( PATH_SEPARATOR );        path.append( artifact.getBaseVersion() ).append( PATH_SEPARATOR );        path.append( artifact.getArtifactId() ).append( ARTIFACT_SEPARATOR ).append( artifact.getVersion() );        if ( artifact.hasClassifier() )        {            path.append( ARTIFACT_SEPARATOR ).append( artifact.getClassifier() );        }        if ( artifactHandler.getExtension() != null && artifactHandler.getExtension().length() > 0 )        {            path.append( GROUP_SEPARATOR ).append( artifactHandler.getExtension() );        }        return path.toString();    }    private String formatAsDirectory( String directory )    {        return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );    }



如:spring-core依赖的pom文件:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.8.RELEASE</version>
</dependency>
该文件的存放位置:"D:\JavaDeveloper\MavenRepository\org\springframework\spring-core\4.2.6.RELEASE\spring-core-4.2.6.RELEASE.jar"
我的本地仓库是:D:\JavaDeveloper\MavenRepository
可以在运行时指定本地仓库位置:mvn clean install -Dmaven.repo.local=/home/juven/myrepo/




远程仓库
1、pom中配置远程仓库(只对当前项目有效,这种配置适用于只有当前maven项目需要使用的构件在其他远程仓库中不存在时):
<project>
……
<repositories>
<repository>
<id>osc</id> 注:maven自带的中央仓库使用的id是central,如果其他仓库使用该id,则会覆盖中央仓库。
<name>OSChina repository</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled> 注:表示开启osc仓库的发布版本下载,默认值是true
</releases>
<snapshots>
<enabled>false</enabled> 注:表示关闭osc仓库的快照版本下载,默认值是false
</snapshots>
</repository>
……
</repositories>
<pluginRepositories>
<pluginRepository>
<id>maven-net-cn</id>
<name>Maven China Mirror</name>
<url>http://maven.net.cn/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
……
</project>


2、在settings.xml中配置远程仓库(对本机所有的maven项目均有效)
<settings>
...
<profiles>
<profile>
<id>dev</id>
<!-- repositories and pluginRepositories here 将POM中的<repositories>及<pluginRepositories>元素复制到这里 -->
</profile>
</profiles>
<activeProfiles>
<activeProfile>dev</activeProfile>
</activeProfiles>
...
</settings>
这样配置后,maven除了从dev下载构件之外,还会时不时的访问中央仓库central。如果希望maven所有的下载请求只通过dev,可以配置镜像。(思考:此处将仓库的id改为central可以达到代理中央仓库的效果吗?)


3、配置镜像
镜像:用于替代无法访问的仓库
setting.xml配置中央仓库的镜像:
<settings>
……
<mirrors>
<mirror>
<id>oschina</id>
<name>Nexus oschina</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<mirrorOf>central</mirrorOf> 注:central,表示为中央仓库的镜像,任何对中央仓库的请求都会转至该镜像。
</mirror>
</mirrors>
……
</settings>

使用私服作为镜像
<settings>
……
<mirrors>
<mirror>
<id>interal-repository</id>
<name>Interal Repository Manager</name>
<url>http://192.168.1.100/maven/</url>
<mirrorOf>*</mirrorOf> 注:*,表示该仓库是所有maven仓库的镜像,任何对远程仓库的请求都会转至http://192.168.1.100/maven/。mirrorof还有其他高级配置就懒得写了。
</mirror>
</mirrors>
……
</settings>

远程仓库
中央仓库:http://repo1.maven.org/maven2/
https://repo.maven.apache.org/maven2/
JBoss Maven库:http://repository.jboss.com/maven2/

国内镜像:
开源中国的maven库:http://maven.oschina.net/content/groups/public/



分发构件至远程仓库
mvn install 会将项目生成的构件安装到本地Maven仓库,mvn deploy 用来将项目生成的构件分发到远程Maven仓库。本地Maven仓库的构件只能供当前用户使用,在分发到远程Maven仓库之后,所有能访问该仓库的用户都能使用你的构件。
我们需要配置POM的distributionManagement来指定Maven分发构件的位置,pom如下:
<project>
...
<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Release Repository</name>
<url>http://127.0.0.1:8080/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://127.0.0.1:8080/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
...
</project>
Maven区别对待release版本的构件和snapshot版本的构件,snapshot为开发过程中的版本,实时,但不稳定,release版本则比较稳定。Maven会根据你项目的版本来判断将构件分发到哪个仓库。
一般来说,分发构件到远程仓库需要认证,如果你没有配置任何认证信息,你往往会得到401错误。这个时候,需要远程仓库的认证,如下在setting.xml中配置认证信息:
<settings>
...
<servers>
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
...
</settings>
需要注意的是,settings.xml中server元素下id的值必须与POM中repository或snapshotRepository下id的值完全一致。将认证信息放到settings下而非POM中,是因为POM往往是它人可见的,而settings.xml是本地的。


仓库搜索服务
http://search.maven.org/
http://mvnrepository.com/



Maven的生命周期是抽象的,其实际行为都由插件来完成。生命周期抽象了构建的各个步骤,定义了他们的次序,但没有提供具体实现。(模板方法Template Method设计模式的体现:在父类中定义算法的整体结构,子类通过实现或重写父类的方法来控制实际的行为。区分工厂方法模式、策略模式)
生命周期包含:项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成……等所有构建步骤。

maven的三套相互独立的生命周期:clear、default、site
每个生命周期包含一些阶段(phase),这些阶段是有次序的,后面的阶段依赖于前面的阶段。

插件:是一个独立的构件,能够完成多个任务(功能)。
插件目标:插件能够完成的每个功能就是一个插件目标。

生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。
如项目编译这个任务,对应了default生命周期的compile阶段,由maven-compiler-plugin这个插件的compile目标完成。

内置绑定:maven在核心为一些主要的生命周期阶段绑定了插件目标,如clear的clear阶段绑定了maven-clear-plugin:clear。
自定义绑定:用户将某个插件目标绑定到生命周期的某个阶段。如:创建项目的源码jar包,pom.xml配置如下
<project>
……
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution> 注:execution用来配置执行一个任务,指定了插件目标maven-source-plugin:jar-no-fork绑定到verify生命周期阶段
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
……
</project>

插件的仓库需要单独配置
<pluginRepositories>
<pluginRepository>
<id>osc</id>
<url>http://maven.oschina.net/content/groups/public/</url>
</pluginRepository>
</pluginRepositories>






maven聚合:pom配置如下:

<project>
……

<groupId>com.ly.car</groupId>
<artifactId>CarOrderBase</artifactId>
<version>${parent.version}</version>
<packaging>pom</packaging> 聚合模块的打包方式必须是pom,否则就无法构建
<name>CarOrderBase</name>
<description>CarOrderBase</description>

<modules>
<module>CarOrderService</module> 被聚合的模块,使用的是相对路径,如果使用平行目录结构,则应该是:../CarOrderService
<module>CarOrderAdmin</module>
<module>CarOrderDSF</module>
<module>CarOrderJob</module>
<module>CarOrderClient</module>
</modules>

……
</project>

继承:定义父模块来消除重复的配置,如spring-core,spring-context等。
步骤:
1、创建一个父模块,只需要定义pom.xml文件即可,packaging方式为pom

2、修改子模块的pom:
<project>
……
<parent>
<groupId>com.ly.car</groupId>
<artifactId>CarOrderBase</artifactId>
<version>${parent.version}</version>
</parent>

<artifactId>CarOrderAdmin</artifactId>
<packaging>war</packaging>
<name>CarOrderAdmin</name>
<description>CarOrderAdmin</description>

<dependencies>
……
</dependencies>

<build>
<plugins>
……
<plugins>
</build>
……
</project>

3、依赖管理:提取子模块的公共依赖到父模块,如:spring的配置、junit等,
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
……
</dependencies>
</dependencyManagement>

4、修改子模块的pom依赖,可以省略配置<version>信息,这样就可以统一整个项目的依赖包的版本号了
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
……
</dependencies>


插件管理:与依赖管理类似,提取公共的插件到父模块中,如:
父模块的pom:
<project>
……
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution> 注:execution用来配置执行一个任务,指定了插件目标maven-source-plugin:jar-no-fork绑定到verify生命周期阶段
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
……
</project>

子模块的pom:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
</plugins>
</build>

聚合与继承的关系:可以融合使用,都是只有pom文件,且pom.xml的packaging必须是pom

查看超级POM中的配置:D:\JavaDeveloper\apache-maven-3.3.9\lib\maven-model-builder-3.3.9.jar 》 \org\apache\maven\model\pom-4.0.0.xml

反应堆:所有组合的模块,如:
<modules>
<module>CarOrderService</module>
<module>CarOrderAdmin</module>
<module>CarOrderDSF</module>
<module>CarOrderJob</module>
<module>CarOrderClient</module>
</modules>

使用Nexus创建私服:暂不打算关注,只需要知道怎么使用私服作为镜像部署构件至远程仓库就行了。见上面已提到过的。





mvn test:使用maven进行测试

使用Jenkins进行持续集成:应该是个很有前途的方向,但是暂时我们项目中都没有这方面的意识,那就暂时不关注了,就算关注了又用不到也没意义,只有实践才是检验真理的唯一标准。


使用maven构建web项目
web项目的目录结构:
-war/
+META-INF/
+WEB-INF/
|+classes/
| | +XXX.class
| | +YYY.properties
| | + ……
|+lib/
| | +dom4j-1.4.1.jar
| | +junit.2.3.4.jar
| | + ……
| + web.xml
|
+image/
|
+ js/
|
+ css/
|
+ index.html


Web项目的maven目录结构:

-project/
|
+pom.xml
|
+src/
+ main/
|+java/
| | +XXX.java
| | + ……
| |
|+resources/
| | +config.properties
| | + ……
| |
|+webapp/
| +WEB-INF/
| | + web.xml
| |
| +image/
| |
| + js/
| |
| + css/
| |
| + index.html
+ test/
+java/
|+resources/


使用jetty-maven-plugin进行测试

使用Cargo实现自动化部署


区分版本管理(Version Management)与版本控制(Version Control)

maven的版本号约定主版本.次版本.增量版本-里程碑版本,如1.3.4-beta-2

Maven属性:
内置属性:${basedir}:表示项目根目录,即包含pom.xml文件的目录,${version}:表示项目版本。
POM属性:pom文件中对应元素的值, 常见pom属性:
${project.build.sourceDirectory}:项目的主源码目录,默认是src/main/java。
${project.build.testSourceDirectory}:项目的测试源码目录,默认是src/test/java。
${project.build.directory}:项目的构建输出目录,默认是target/。
${project.outputDirectory}:项目的主源码目录,默认是target/classes。
${project.testOutputDirectory}:项目的测试代码编译输出目录,默认是target/testclasses。
${project.groupId}:项目的groupId。
${project.artifactId}:项目的artifactId。
${project.version}:项目的version,与${version}等价。
${project.build.finalName}:项目打包输出文件的名称,默认是${project.artifactId}-${project.version}。
自定义属性:
<properties>
<my.property>value</my.property>
</properties>
settings属性:引用settings.xml文件中xml元素的值,如${settings.localRepository}指向本地仓库的地址
Java系统属性:如${user.home}指向用户目录,可使用mvn help:system查看所有的Java系统属性。
环境变量属性:如${env.JAVA_HOME}指向JAVA_HOME环境变量的值,可使用mvn help:system查看所有的环境变量。



……懒得写了……

从自己的笔记本拷过来的~格式又乱了~内含个人信息~请勿乱来,还有前两天发布的那个也是的。

----------------------------<hr>分割线-----------------------

2016-7-15:今天来加点东西,现在换项目了,差不多所有的东西都用到了

灵活的构建:
不同环境中项目使用不同的方式进行构建,比如最常见的是数据库的配置,
在src/main/resources/目录下有一份数据库的配置文件:
#database
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
这份文件是针对本地开发时使用的,上线测试或部署时就分别使用不同的数据库配置,那么这份文件就得改,为了减少工作量(因为懒),使用maven属性将这些变化的部分提取出来:
#database
jdbc.driver=${db.driver}
jdbc.url=${db.url}
jdbc.username=${db.username}
jdbc.password=${db.password}
然后在pom.xml中定义这些maven属性:
<profiles>
<profile>
<id>dev</id>
<properties>
<db.driver>com.mysql.jdbc.Driver<db.driver>
<db.url>jdbc:mysql://localhost:3306/test<db.url>
<db.username>root<db.username>
<db.password>root<db.password>
</properties>
</profile>
</profiles>
然后,还得在配置文件中(哪个配置文件?)为资源目录开启过滤:
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
(过滤就是替换的意思,就是使用maven属性值将引用了maven属性的地方全部替换,因为编译时会将主资源目录下的资源文件全部编译到target/classes目录下,所以在此指定项目的/src/main/resources目录下的资源文件中引用的maven属性全部替换成pom中设定的值,这就像是开启了过滤一样)
最后最后:还得激活profile
mvn install -Pdev  :-P是激活Profile的意思,应该要大写,dev是指pom中profile的id,-Pdev连写不要有空格

profile激活的方式有多种。命令行激活、setting激活、默认激活……





2 0