您的位置:首页 > 其它

Maven学习总结(二)——Maven依赖

2017-04-09 19:45 232 查看
     1·何为maven依赖?
     何为依赖?我要和我的好朋友打电话,如果啥都没有,这事肯定办不了,所以,我需要借助于手机来帮助我完成此项任务。此时手机就充当了“依赖”的角色。
     同理,maven依赖里,功能单一化的原则,迫使我们不得不站在巨人的肩膀上,借助第三方封装好的工具,来帮助我们完成想要完成的工作。很幸运的是,我们不用去各个官网下载我们需要的各个jar包,这一切,Maven先生看来眼里,怎舍得高薪资的程序猿浪费时间于查找jar上?so,Maven先生说了,只要你们声明你们想要的东西,我都会主动推送给你们。这个时候,我们只要进行 依赖配置,想要的自然会推送过来。
        

 2·Maven依赖配置

<project>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<type>...</type>
<scope>test</scope>
<optional>...</optional>
<exclusions>
<exclusion>
<groupId>...</groupId>
<artifactId>...</artifactId>
</exclusion>
</exclusions>
</ependency>
</dependencies>
</project>


      3·maven依赖范围

依赖范围控制依赖与三种classpath(编译classpath,测试classpath,运行classpath)的关系。其中,依赖          范围通过scope标签来达到依赖范围的控制。该scope标签的可取值为:

·compile

·test

·provided

·runtime

·system

·import

          值为compile时,指该jar包将影响项目的三种classpath路径,即在测试,编译,运行都有该jar包且可依赖。

          值为test时,指该jar包将只影响测试classpath路径下的代码,什么意思呢?1·在编译情况下不识别:如在         maven默认的源代码路径下src/main/java,中使用@test注解,编译会报错(可自行尝试);2·在运行情况下不可用:如项目最后打好的war包并无junit的依赖。

          值为provided时,指该jar包只作用于编译和测试classpath,在项目最后打成的war包不存在该类jar包。怎么讲?若项目部署再tomcat的web服务器上,tomcat本身可提供jsp-api.jar,servlet-api.jar两个jar构件,则在项目中可将这两个jar包都打上provided值的scoped标签,这样可减少重复jar包依赖以及减少依赖版本冲突。

           值为runtime时,指该jar包只作用于测试和运行classpath,即编译情况下不需要该jar包的参与。如JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。

system和import不常用,这里不做解释。

4·maven传递依赖机制
     何为传递依赖:A直接依赖于B,B直接依赖于C,则C会被间接传递依赖到A中。
     优点:考虑一个基于Spring Framework的项目中,如果不使用maven,那么在项目中就需要下载相关依赖,但又
由于Spring Framework会依赖于其它类库,所以,我们就要把和Spring
Framework以及相关的所有jar包加载到我们的项目中,这个时候就会加大我们的管理成本,而Maven传递依赖机制的引入,就很好的解决了这个问题。Maven会解析各个直接依赖的POM,将那些有必要的间接依赖,以传递性依赖的形式引入到当前的项目中。
    缺点:1·影响项目的稳定性:若项目中依赖于spring Framework,而Spring Framework又依赖于某个快照版本的jar包,此时,就会增加本身项目的不稳定因素。
          2·不方便管理。和maven的最佳实践相矛盾。详情请看5最佳实践中的demo分析。

5·最佳实现
1·排除依赖
    maven传递依赖机制的引入,大大简化了我们的工作,但同时,也会给我们带来一些困扰,比如说,我们
的项目依赖于一个第三方jar包,而由于某种原因,这个第三方jar包同时依赖另一个类库的SNAPSHOT版本,那个这个SNAPSHOT版本就会被传递依赖到我们项目中,这样的版本很有可能直接影响到我们的项目,所以,我们就要排除掉该依赖。
    代码中使用exclustions元素声明排除依赖,注意:声明exclusion的时候只需要groupId和artifactId即可。

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<artifactId>netty</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>


2·归类依赖
看如下两端代码的区别:
    使用常量不仅让代码变得更加简洁,更重要的是可以避免重复,在需要更改PI的地方,只需要修改一处即可,降低了错误发生的概率。

//方式1
public double c(double r){
return 2*3.14*r;
}
public double s(double r){
return 3.14*r*r;
}

//方式2
public final double PI=3.14;
public double c1(double r){
return 2*PI*r;
}
public double s1(double r){
return PI*r*r;
}


     同理,在项目开发中往往会引入同一个项目中的多个jar包,比如最常见的spring,如果我们项目中用到很多关于SpringFramework的依赖,它们分别是spring-core-3.2.8.RELEASE,spring-beans-3.2.8.RELEASE,spring-context-3.2.8.RELEASE,它们都是来自同一项目的不同模块。因此,所有这些依赖的版本都是相同的,而且可以预见,如果将来需要升级SpringFramework,这些依赖的版本会一起升级。
     因此,我们应该在一个唯一的地方定义版本,并且在dependency声明引用这一版本,这一在SpringFramework升级的时候只需要修改一处即可。首先使用properties元素定义Maven属性,实例中定义了一个<springframework.version>子元素,其值为3.2.8.RELEASE,有了这个属性定义之后,Maven运行的时候会将pom.xml中所有的${springframework.version}替换成实际的值:3.2.8.RELEASE。也就是可以使用$和{}的方式引用Maven的属性。然后将所有springframework依赖的版本替换成<version>${springframework.version}</version>这个样子,就和在Java代码中定义了一个不变的常量一样,以后要升级版本就只需要把这个值改了。如下代码:

<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指定了当前POM模型的版本,对于maven2及maven3来说,它只能是4.0.0 commented by
bill 2017-1-7 -->
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.dynamic</groupId>
<artifactId>itoo-jboss-project-root</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../itoo-jboss-project-root/pom.xml</relativePath>
</parent>

<artifactId>itoo-basic-parent</artifactId>
<packaging>pom</packaging>

<properties>
<commons-collections.version>3.2.1</commons-collections.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons-collections.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

3·优化依赖
       ·当前已解析依赖:mvn dependency:list
       ·依赖分析:mvn dependency:analyze
       ·依赖树分析:mvn dependency:tree>1.txt
在项目中我们进行过一次大型的pom重构,当时项目中存在的主要问题是:maven管理混乱。所以当时我们是通过依赖分析,按照maven的最佳实践对我们的项目进行大型的重构。下面,我拿一个简单的demo来分析,大家好好看哦!
·pom文件如下(主要看spring的相关配置):

<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"> <modelVersion>4.0.0</modelVersion>
<groupId>com.mark</groupId>
<artifactId>mark</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>mark Maven Webapp</name>
<url>http://maven.apache.org</url>

<properties>
<spring.version>4.0.4.RELEASE</spring.version>
<hibernate.version>4.3.5.Final</hibernate.version>
<junit.version>3.8.1</junit.version>
<hibernate-validator.version>5.1.2.Final</hibernate-validator.version>
<c3p0.version>0.9.1.2</c3p0.version>
<mysql.version>5.1.31</mysql.version>
<jackson-databind.version>2.4.2</jackson-databind.version>
<jstl.version>1.2.1</jstl.version>
<standard.version>1.1.2</standard.version>
<tomcat.version>5.5.23</tomcat.version>
</properties>

<dependencies>

<!--测试相关-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--spring相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--hibernate相关依赖-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!--mysql及连接池相关依赖-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>

<!-- Jackson Json处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<!--jsp相关-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>${standard.version}</version>
</dependency>
<dependency>
<groupId>tomcat</groupId>
<artifactId>servlet-api</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>tomcat</groupId>
<artifactId>jsp-api</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>mark</finalName>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>


从pom结构中可以看出,关于spring的依赖只有两个,那么接下来我们就来分析一下该pom文件:

执行命令:mvn dependency:analyze,分析结果如下:



图中圈住的是关键内容,可以看出有两部分
使用未声明部分:指项目中需要这些jar包的依赖但是没有显示声明,
声明未使用部分:指项目中显示声明了但没有使用(仅限编译阶段,运行阶段检测不出来需再次分析)
这里我们还是主要看关于spring的相关依赖,可以发现pom中显示声明的webmvc依赖出现在声明未使用部分,而其他如核心jar包如spring-beans等出现在使用未声明部分,问题是,为什么核心jar包没有在项目中依赖,也不影响项目的正常运行呢?
    下面结合依赖树一起来分析:
    输入命令:mvn dependency:tree,结果如下:



只看spring相关的依赖树,发现,spring的一些核心jar文件被spring-webmvc传递依赖过来了,这也就是为什么项目中不显示声明也不影响使用的原因。但是这样做,不符合maven的最佳实践,最佳实践我们应该怎么做呢?就是按照依赖分析的那张图解决:使用未声明部分我们统统显示声明在pom结构里,声明未使用部分分析后我们再去删除相应jar文件,修改后如下(只显示依赖项)

<dependencies>

<!--测试相关-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--spring相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--hibernate相关依赖-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<!--mysql及连接池相关依赖-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>

<!-- Jackson Json处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>


再次依赖分析,结果如下:



会发现使用未声明部分不见了,也就是我们都在pom中显示声明了,但是未使用但声明部分还存在,这部分的依赖就要一个个的分析是否被依赖了,比如说junit,不能删,因为需要测试,jackson依赖不能删,因为json文件的解析需要改依赖,这些都是编译环境下无法检测出的,所以,通过分析后再做决定就ok了。
    好了,这就是整个依赖解析优化的过程,也是对maven最佳实践的一个实现。

关于maven的依赖部分就暂时告一段落了,感兴趣的亲们一起交流哦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  maven 依赖