Dev Tools

《Maven实战》笔记 5.1 – aggregation

Maven项目大了,就要拆成多个小项目。这就是aggregation要干的事。 具体来说,就是要在各个小项目建好之后,再建一个专们用于聚合的项目。在这个项目的pom.xml里声明: <!–此类项目的打包方式必须为pom–> <packaging>pom</packaging> <!–在这里声明小项目–> <modules> <!–module-base, module-app是小项目的目录名–> <module>module-base</module> <module>module-app</module> </modules> 对这个项目执行一下"mvn package", Maven会自动构建小项目module-base 和 module-app 如果执行"mvn package -pl module-base",则Maven只构建module-base

《Maven实战》笔记 5.2 – 继承

继承是为了实现“在父项目里声明,在各个子项目里使用”,比如项目的版本、项目的groupId、依赖等。 下面是项目module-base的pom.xml的片段 <!–module-base将继承module-root–> <parent> <groupId>mvn-module</groupId> <artifactId>module-root</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <!–这里不必再显式声明groupId和version。项目会自动从父项目中继承–> <artifactId>module-base</artifactId> ======================================== Super Pom   java中每个类都是java.lang.Object的子类,maven中每个项目的pom都是Super Pom的子pom. Super Pom是Maven内置的顶级Pom,Maven项目的默认目录结构就是在这里定义的。 ========================================= 对“依赖”的继承是最主要的用处之一。最佳实践是: 1. 父项目的pom.xml通过<dependencyManagement>声明所有会用到的dependency 2. 子项目的pom.xml通过<dependencies>声明所需的依赖。声明中不需要指明所依赖的构件的版本。 说明: 1.为什么要在父项目的pom中集中声明所有依赖? 因为这样可以保证,对同一个构件,所有子项目都会使用相同的版本。 2.为什么父项目中要用<dependencyManagement>而不直接用<dependencyies> ? 因为如果用后者,其中定义的dependency会被所有子项目继承,子项目在打包时会把这些构件打在自己的包中,即使这个子项目并不需要某些dependency.

《Maven 实战》笔记3.1 – Repository的概念及其在项目中的使用

1. Repository用来存放maven项目的构件,如pom, *.jar, *-source.jar等,它的布局像一个文件系统,有路径(目录)和文件 2. 使用Maven时,你会跟两类Repository打交道。    a. 存放在你本机那些的构件即组成“ 本地Repository”    b. 不在你本机的、存在服务器上的叫“ 远程Repository"。    当Maven需要构件时,首先会在本地Repository里找,找不到才去远程Repository中找。 3. Repository是相对于项目而言的,所以 你可以在项目级别配置远程的Repository,而且可以配多个。    一个Repository是一个 id + url + 其它信息的组合。id你可以随便取,url则是远程Repository的确切地址。 <project> <repositories> <repository> <id>jboss</id> <name>jboss</name> <url>https://repository.jboss.org/nexus/content/repositories/</url> … </repository> <repository> <id>google</id> <name>google</name> <url>http://google-maven-repository.googlecode.com/svn/repository/</url> … </repository> </repositories> … </project> 对此你可能有多种疑问: 问:项目里配了两个repository,那下载构件时,Maven去哪个repository呢? 答案:测试表明,Maven会先去定义在最前面的repository即"jboss"里去找; 如果找不到,再去"google"找 问:如果jboss和google里都找不到呢? 答:就去Maven默认的central repository里去找,它的id是"central", url是http://repo1.maven.org/maven2. 这个配置写死在maven的某个jar里面 问:如果我把上面的jboss repository换成"central"会怎么样? <project> …

《Maven 实战》笔记3.1 – Repository的概念及其在项目中的使用 Read More »

《Maven 实战》笔记3.2 – 让Repository区别对待snapshot版本和release版本

可以让Repository区别对待snapshot版本和release版本。也就是说,你可以只从jboss repository中下载release版本,并只从google repository中下载snapshot版本。      另外,考虑到本地Repository相当于远程Repository的缓存,应该设置一下缓存的更新频率,提供snapshot的repository更要设置(当然,也可以不显式设置,默认值是daily)         <repository> <!– … –> <releases> <!– 本repository不提供release版本下载 –> <enabled>false</enabled> </releases> <snapshots> <!– 本repository提供snapshot版本下载 –> <enabled>true</enabled> <!– 缓存每超过五分钟就要更新–> <updatePolicy>5</updatePolicy> </snapshots> <!– … –>   

《Maven 实战》笔记3.3 – internal repository与mirror

    internal repository是指在局域网内部搭建的repository,它跟central repository, jboss repository等的区别仅仅在于其URL是一个内部网址     mirror则相当于一个代理,它会拦截去指定的远程repository下载构件的请求,然后从自己这里找出构件回送给客户端。配置mirror的目的一般是出于网速考虑。     可以看出, internal repository和mirror是两码事。前者本身是一个repository,可以和其它repository一起提供服务,比如它可以用来提供公司内部的maven构件;而后者本身并不是repository,它只是远程repository的网络加速器。     不过,很多internal repository搭建工具往往也提供mirror服务,比如Nexus就可以让同一个URL,既用作internal repository,又使它成为所有repository的mirror

《Maven实战》笔记 2.4 - Optional依赖

Optional依赖:   假设App依赖了A, A“可选”地依赖了B,那App在打包时,会不会纳入B?   答案:不会。如果你的App里需要用到A中跟B相关的功能,那就需要把B用作App的直接依赖。  可选依赖不是什么好东西,它搞得你把传递依赖升级为直接依赖,很容易令人困惑,你的同事会问:为什么App要直接依赖B?   如果A对B有可选依赖,则应该把A拆成两个项目,其中A1依赖B,A2不依赖B,App再按需选择  

《Maven实战》笔记 2.3 - 传递依赖:Maven的核心竞争力之一

如果你的项目要引入Spring,而你又不用Maven,你怎么把Spring本身所需的jar文件找出来?   1.办法一:先只纳入spring.jar,然后创建你的应用,根据编译和运行时的错误,结合Spring的文档,把Spring所需的第三方jar一个一个下载,再纳入进来 — 不用说,会费劲死   2.办法二:把spring-with-dependencies.zip包里的spring.jar和第三方库一次性纳入进来,这样是省事很多,但你纳入的第三方库存在两个问题:     a.有些则可能和你已经存在的第三方库重复(如apache-commons系列),但版本不一样。这时你就得手动解决这种重复问题,即选择留下哪个,去掉哪个     b.有些库可能并不需要纳入进来,因为spring只是某块功能会用到它们,而这块功能你的应用根本用不上。这些不需要的库放在你的应用里,很容易跟未来引入的其他第三方库重复(比如引入Hibernate时也要引入apache-commons系列),到时又会产生跟#a一样的问题。 Maven可以自动化地解决这些问题。   1. 你只需要宣称依赖Spring   2. Spring所需要的类库会被Maven自动下载下来,不需要你手动下   3. 如果这时存在第三方库的重复问题,Maven会自动为你做好依赖的调解

《Maven实战》笔记 2.6 – Used undeclared 和 Unused declared

你的项目会直接依赖一些项目,也可能会传递依赖一些项目;有的直接依赖,可能你本应该降格为传递依赖;有的传递依赖,你可能应该用作直接依赖;还有些直接依赖,可能你已经用不上应该去掉了。 mvn dependency:analyze就是用来帮你发现上述情况的一条命令。它会对两种情况作出警告:   1. Used undeclared dependencies。 你的App的代码直接调用了B里的API,但当前B是通过App->A->B的关系被纳入到Classpath的。这种情况下,你应该将B升级为直接依赖。否则的话,如果A不再依赖B了,你依赖B的那些代码就会有编译错误,而且可能是很难找到原因的编译错误。   2. Unused declared dependencies。你的App的代码没用直接调用B里的API,但却把B声明为App的直接依赖。 这种情况下,你要谨慎     a.App可能确实不需要直接依赖B,不过,可能会这样:App->A,A调用了B里的API,但A的pom里没有声明B。如果A的作者不负责任,这种情况就会出现,而且在大型组织里经常会遇到。这种情况下,你就要仍然把B留下来作为依赖,否则运行时A就会说找不到B而报错。     b.App的java代码里不需要直接依赖B,但是经过xml配置文件或者以反射方式调用了B里的API,这种情况下你也要保留B作为直接依赖。     c.App依赖了A,A依赖了B,这时你可以去除对B的直接依赖     d.App没有调用B里的代码,App的其他所有直接依赖和传递依赖的pom里都没有依赖B,也没有调用B里的API,这时也应该去除对B的直接依赖。 要判断App打包后是否需要B出现在classpath里,可以使用JarJar工具。它可以分析App打包后、包里所有的jar文件之间的java调用关系。

《Maven实战》笔记 2.5 - 依赖的调解

Maven的依赖调解机制     1.如果存在App->A->B-0.9, 又存在App->C->D->B-1.0,那App在打包时会不会把B-0.9和B-1.0都纳入进来?如果不会,倒底选择哪个B?    答案:只会纳入一个,即B-0.9,因为它离App较近(中间只隔了一个A,B-1.0和App之间则隔了D,C两个)   2.App到B存在两条依赖路径,怎么识别这种情况?    答案: mvn dependency:tree -Dverbose,它会显示哪些项目由于这种情况而被“omitted for conflict”   3.B-0.9被选中,会不会导致依赖B-1.0的D在运行时出错?    答案:会的。如果D依赖了B-1.0中有而B-0.9里没有的东西,就会在运行时出错   4.那该怎么办?    答案:      办法1. 在App的pom里,屏蔽掉A对B的依赖 <dependency> <groupId>kent.learn</groupId> <artifactId>maven-a</artifactId> <exclusions> <exclusion> <groupId>kent.learn</groupId> <artifactId>maven-b</artifactId> </exclusion> </exclusions> </dependency>      办法2. 让App直接依赖B-1.0,让其他的对B的传递依赖都失效

《Maven实战》笔记 1 - 一些杂碎

Maven的三大功能   1.构建: 类似于Ant,但比Ant更强调Convention Over Configuration,有利于在组织内形成标准   2.依赖管理:这一点应该是Maven最重要的特性   3.项目信息管理:好像第三方框架才用这种东西? Eclipse插件   1.可以装一个m2eclipse   2.m2eclipse自带了一个Maven,应该配置一下,让它使用你安装的正牌Maven;这是为了让整台机器只使用一个Maven,避免两个Maven都作用于同一个工程,造成难以预料的错误。 杂   1.pom.xml里的<name>元素没有多大实际作用,你可以填一下可读性较好的项目名称,如"web module of xxx platform"   2.java类的包名应该包含本工程的groupId和artifactId