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

     1·何为maven依赖?

     何为依赖?我要和我的好朋友打电话,如果啥都没有,这事肯定办不了,所以,我需要借助于手机来帮助我完成此项任务。此时手机就充当了“依赖”的角色。

     同理,maven依赖里,功能单一化的原则,迫使我们不得不站在巨人的肩膀上,借助第三方封装好的工具,来帮助我们完成想要完成的工作。很幸运的是,我们不用去各个官网下载我们需要的各个jar包,这一切,Maven先生看来眼里,怎舍得高薪资的程序猿浪费时间于查找jar上?soMaven先生说了,只要你们声明你们想要的东西,我都会主动推送给你们。这个时候,我们只要进行 依赖配置,想要的自然会推送过来。         


 2·Maven依赖配置

      
      
        
             junit      
             junit      
             3.8.1
             ...
             test
             ...
                   
                       
                   ...      
                   ...      
                  
                 
                  
             
   


      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不常用,这里不做解释。

maven传递依赖机制

     何为传递依赖:A直接依赖于BB直接依赖于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的时候只需要groupIdartifactId即可。


	org.apache.zookeeper
	zookeeper
	${zookeeper.version}
	
		
			org.slf4j
			slf4j-log4j12
		
		
			netty
			io.netty
		
	
	


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属性,实例中定义了一个子元素,其值为3.2.8.RELEASE,有了这个属性定义之后,Maven运行的时候会将pom.xml中所有的${springframework.version}替换成实际的值:3.2.8.RELEASE。也就是可以使用$和{}的方式引用Maven的属性。然后将所有springframework依赖的版本替换成${springframework.version}这个样子,就和在Java代码中定义了一个不变的常量一样,以后要升级版本就只需要把这个值改了。如下代码:



	
	4.0.0

	
		com.dynamic
		itoo-jboss-project-root
		0.0.1-SNAPSHOT
		../itoo-jboss-project-root/pom.xml
	


	itoo-basic-parent
	pom

	
             3.2.1
        
       
           
	               
				commons-collections
				commons-collections
				${commons-collections.version}
			
            
	

3 ·优化依赖

       ·当前已解析依赖:mvn dependency:list

       ·依赖分析:mvn dependency:analyze

       ·依赖树分析:mvn dependency:tree>1.txt

在项目中我们进行过一次大型的pom重构,当时项目中存在的主要问题是:maven管理混乱。所以当时我们是通过依赖分析,按照maven的最佳实践对我们的项目进行大型的重构。下面,我拿一个简单的demo来分析,大家好好看哦!

·pom文件如下(主要看spring的相关配置):


  4.0.0
  com.mark
  mark
  war
  1.0-SNAPSHOT
  mark Maven Webapp
  http://maven.apache.org

  
    4.0.4.RELEASE
    4.3.5.Final
    3.8.1
    5.1.2.Final
    0.9.1.2
    5.1.31
    2.4.2
    1.2.1
    1.1.2
    5.5.23
  

  

    
    
      junit
      junit
      ${junit.version}
      test
    
    
    
      org.springframework
      spring-webmvc
      ${spring.version}
    
    
      org.springframework
      spring-orm
      ${spring.version}
    
  
    
      org.hibernate
      hibernate-validator
      ${hibernate-validator.version}
    
    
      org.hibernate
      hibernate-core
      ${hibernate.version}
    
    
    
      c3p0
      c3p0
      ${c3p0.version}
    
    
      mysql
      mysql-connector-java
      ${mysql.version}
    

    
    
      com.fasterxml.jackson.core
      jackson-databind
      ${jackson-databind.version}
    
    
    
      javax.servlet.jsp.jstl
      javax.servlet.jsp.jstl-api
      ${jstl.version}
    
    
      taglibs
      standard
      ${standard.version}
    
    
      tomcat
      servlet-api
      ${tomcat.version}
      provided
    
    
      tomcat
      jsp-api
      ${tomcat.version}
      provided
    
  
  
    mark
    
      
      
        org.apache.tomcat.maven
        tomcat7-maven-plugin
        2.2
        
          8080
          /
        
      
    
  


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

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

Maven学习总结(二)——Maven依赖_第1张图片

图中圈住的是关键内容,可以看出有两部分

使用未声明部分:指项目中需要这些jar包的依赖但是没有显示声明,

声明未使用部分:指项目中显示声明了但没有使用(仅限编译阶段,运行阶段检测不出来需再次分析)

这里我们还是主要看关于spring的相关依赖,可以发现pom中显示声明的webmvc依赖出现在声明未使用部分,而其他如核心jar包如spring-beans等出现在使用未声明部分,问题是,为什么核心jar包没有在项目中依赖,也不影响项目的正常运行呢?

    下面结合依赖树一起来分析:

    输入命令:mvn dependency:tree,结果如下:

Maven学习总结(二)——Maven依赖_第2张图片

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



    
    
      junit
      junit
      ${junit.version}
      test
    
    
    
      org.springframework
      spring-webmvc
      ${spring.version}
    
    
      org.springframework
      spring-tx
      ${spring.version}
    
    
      org.springframework
      spring-beans
      ${spring.version}
    
    
      org.springframework
      spring-context
      ${spring.version}
    
    
      org.springframework
      spring-web
      ${spring.version}
    
    
      org.springframework
      spring-orm
      ${spring.version}
    
  
    
      org.hibernate
      hibernate-core
      ${hibernate.version}
    
    
      org.hibernate.javax.persistence
      hibernate-jpa-2.1-api
      1.0.0.Final
    
    
      javax.validation
      validation-api
      1.1.0.Final
    
    
    
      c3p0
      c3p0
      ${c3p0.version}
    
    
      mysql
      mysql-connector-java
      ${mysql.version}
    

    
    
      com.fasterxml.jackson.core
      jackson-databind
      ${jackson-databind.version}
    

    
      commons-fileupload
      commons-fileupload
      1.3.1
    
  

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

Maven学习总结(二)——Maven依赖_第3张图片

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

    好了,这就是整个依赖解析优化的过程,也是对maven最佳实践的一个实现。


关于maven的依赖部分就暂时告一段落了,感兴趣的亲们一起交流哦!



你可能感兴趣的:(Maven学习)