Maven实战(2):Maven使用入门

Maven实战(二):Maven使用入门

1.编写POM:它能让项目对象模型与实际代码相独立,我们称之为解耦
Maven项目的核心是pom.xml
pom(Project Object Model:项目对象模型)
 
<?xml version="1.0" encoding="UTF-8"?>
XML文档的版本和编码方式
 

<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/maven-v4_0_0.xsd">
 
</project>
project 是pom.xml的根元素,它还申明了POM相关的命名空间和xml元素
 

<modelVersion>4.0.0</modelVersion>

当前POM模型的版本,对于Maven 2和 Maven 3,它只能是4.0.0
 
 <groupId>org.springside.examples</groupId>
 <artifactId>quickstart</artifactId>
 <version>4.2.3-GA</version>
这三个元素定义了一个项目的基本坐标,在maven的世界里,任何的jar,pom或者war都是以这些基本的坐标进行区分的
 
 
 <groupId>org.springside.examples</groupId> 
groupId定义了项目属于哪个组,这个组往往和项目所在的组织或者公司存在关联。
com.公司名.项目名
com.house.crm
 
 <artifactId>quickstart</artifactId>
artifaceId定义了当前Maven项目在组中唯一的ID
前面的groupId为com.house.crm,你可能会为不同的模块分配artifactId,比如:
crm-util
crm-web
crm-domain
 
 <version>4.2.3-GA</version>
version指定了项目的当前版本
1.0-SNAPSHOT
SNAPSHOT意为快照,说明项目还处于开发中,是不稳定的版本
 

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>${junit.version}</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
groupId,artifactId,version是任何一个Maven项目最基本的坐标
有了这段声明,Maven就能够自动下载junit-4.7.jar,Maven会自动访问*仓库(http://repo1.maven.org/maven2/)
 
<scope>test</scope>
scope是依赖范围,若依赖范围为test,则表示该依赖至对测试有效
如果不声明依赖范围,那么默认值就是compile,则表示该依赖对主代码和测试代码都有效
 
 
2.3.编写主代码
项目的主代码
    Maven约定路径:src/main/java
    是否会被打包到最终的构件中:是
    
    mvn命令:
    mvn clean compile
 
    clean:清理输出目录target,删除target/目录
    compile:编译项目主代码,输出到target/目录
    
    clean:clean
    resources:resources
    compiler:compile
 
 
 
项目的测试代码
    Maven约定路径src/test/java
    是否会被打包到最终的构件中:否
    
    mvn clean test
    
    clean:clean
    resources:resources
    compiler:compile
    resources:testResources
    compiler:testCompile
 
4.打包和运行
    
    mvn clean package
    POM中没有指定打包类型,使用默认打包类型jar
    
    mvn会在打包前执行编译,测试等操作
    jar:jar负责打包,其实就是jar插件的jar目标将主代码打包成名为:crm-example-1.0-SNAPSHOT.jar
 
    它是根据artifaceId-version.jar进行命名的
    
    mvn clean install
    在打包以后,又执行了安装任务install:install.
    Maven会根据POM配置自动下载所需要的依赖构件,执行编译,测试,打包等工作,最后将项目生成的构件    crm-example-1.0-SNAPSHOT.jar
    安装到本地仓库中
    C:\Users\3333\.m2\repository\com\house\crm\crm-example\1.0-SNAPSHOT
    crm-example-1.0-SNAPSHOT.jar
    crm-example-1.0-SNAPSHOT.pom
        
 
   命令执行顺序
    mvn clean compile
    mvn clean test
    mvn clean package    
    mvn clean install    
    
    默认打成的jar是不能够直接运行的,因为带有main方法的类信息是不会添加到manifest中
    (打开jar文件中的META_INF/MAINFEST.MF文件)
 
 
5.使用Archetype生成项目骨架
 
cmd
echo %JAVA_HOME%
 
 
 

6依赖

(6.1)依赖的配置
 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <type></type> 
   <scope>test</scope>
   <optional></optional>
   <exclusions>
       <exclusion></exclusion>
       <exclusion></exclusion>
    </exclusions>    
  </dependency>
 </dependencies>
  
type:依赖的类型,对应于项目坐标定义的packaging.大部分情况下,该元素不必声明,其默认值为jar
scope:依赖的范围
optional:标记依赖是否可选
exclusions:用来排除传递性依赖
 
    
(6.2)依赖的范围
Maven编译主代码----------编译classpath
Maven在编译和执行测试----------测试classpath
运行Maven项目----------运行classpath
 
Maven依赖范围:
compile:编译,测试,运行的时候都需要该依赖
test:编译测试代码以及运行测试代码的时候需要该依赖
provided:编译和测试项目的时候需要该依赖,在运行项目的时候就不需要了,servlet-api
runtime:测试和运行classpath有效,但在编译主代码时候无效,JDBC驱动
system:系统依赖范围。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定的,可能造成构件的不可移植
import:导入依赖范围。
 
 
 
(6.3)依赖的范围
(6.3.1)何为传递性依赖
spring-framework-2.5.6-with-dependencies.zip
 
我们的工程依赖【org.springframeworkspring-core:2.5.6】
【org.springframeworkspring-core:2.5.6】依赖 【commons-logging】
 
 
(6.3.1)传递性依赖和依赖范围
依赖范围不仅控制依赖和三种classpath的关系,还对传递依赖产生影响
A依赖B:第一直接依赖
B依赖C:第二直接依赖
A依赖C:传递性依赖
 
第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围
 
 
(6.4)依赖调解
第一原则:路径最近者优先
第二原则:第一声明优先
 
(6.5)可选依赖
A依赖B,B依赖X(可选)
A依赖B,B依赖Y(可选)
 
X,Y是可选依赖,依赖不得已传递,X,Y将不会对A有任何影响
 
 
理想情况下,是不应该有可选依赖的,在面向对象设计中,有一个单一职责性原则,意指一个类应该只有一项职责
 
上述例子更好的做法应该是为MySQL和PostgreSQL分别创建一个Maven项目,
基于同样的groupId
分配不同的artifaceId
 
com.house.crm:example-mysql
com.house.crm:example-postgresql
 
 
(6.5)最佳实践
传递性依赖会给项目隐式地引入许多依赖
(6.5.1)排除依赖
 
 
项目A依赖项目B,但由于一些原因,不想引入传入性依赖C
而是自己显示地声明对于项目C1.1.0版本的依赖
<exclusions>
    <exclusion>
        <groupId>org.springside.examples</groupId>
        <artifactId>quickstart</artifactId>
    </exclusion>
</exclusions>
 
exclusion排除性依赖的时候,只需要传入groupId和artifactId,这是因为只需要传入groupId和artfactId就能唯一定位依赖图中的某个依赖
 
(6.5.2)归类依赖
    <properties>
    <spring.version>4.0.5.RELEASE</spring.version>
    </properties>
    
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-framework-bom</artifactId>
    <version>${spring.version}</version>
    <type>pom</type>
    <scope>import</scope>
   </dependency>
 
(6.5.3)优化依赖
mvn dependency:list
mvn dependency:tree
 
mvn dependency:analyze
    used undeclared dependencies
    项目中使用的,但没有显示声明的依赖
    风险:这种依赖是通过传递依赖进来的,当升级直接依赖的时候,相关传递性依赖的版本可能发生变化
    优化:显示声明任何项目中直接调用的依赖
    
    unused undeclared dependencies
    项目中未使用的
    dependency:analyze只会分析编译主代码和测试主代码需要用到的依赖,但是一些执行测试和执行运行的依赖它是发现不了的
    优化:不应该删除依赖声明