简述Gradle在大型Java项目上的应用---(一)
2014-07-21 22:40
218 查看
在Java构建工具的世界里,先有了Ant,然后有了Maven。Maven的CoC[1]、依赖管理以及项目构建规则重用性等特点,让Maven几乎成为Java构建工具的事实标准。然而,冗余的依赖管理配置、复杂并且难以扩展的构建生命周期,都成为使用Maven的困扰。
Gradle作为新的构建工具,获得了2010 Springy大奖,并入围了2011的Jax最佳Java技术发明奖。它是基于Groovy语言的构建工具,既保持了Maven的优点,又通过使用Groovy定义的DSL[2],克服了 Maven中使用XML繁冗以及不灵活等缺点。在Eugene Dvorkin撰写的文章《最让人激动的5个Java项目》中,他是这样介绍Gradle的:
“工程自动化是软件项目成功的必要条件,而且它应该实现起来简单、易用、好玩。构建没有千篇一律的方法,所以Gradle没有死板的强加方法于我们,尽管你会认为查找和描述方法很重要,然而Gradle对于如何描述有着非常好的支持。我不认为工具能够拯救我们,但是Gradle能给你所需要的自由,你可以利用Gradle构建易描述的、可维护的、简洁的、高性能项目”。
在最近半年里,我在使用Gradle作为构建脚本的大型Java项目上工作,更深切体会到Gradle在项目构建过程中是如此的简单、易用。
1. 多Module的项目
Hibernate项目负责人Steve Ebersole在Hibernate将构建脚本从Maven换成Gradle时,专门写了一篇文章《Gradle: why?》,文中提到Maven的一个缺点就是:Maven不支持多module的构建。在Micro-Service[3]架构风格流行的今天,在一个项目里面包含多个Module已成为一种趋势。Gradle天然支持多module,并且提供了很多手段来简化构建脚本。在Gradle中,一个模块就是它的一个子项目(subproject),所以,我使用父项目来描述顶级项目,使用子项目来描述顶级项目下面的模块。
1.1 配置子项目
在多模块的项目中,Gradle遵循惯例优于配置 (Convention Over Configuration)原则。
在父项目的根目录下寻找settings.gradle文件,在该文件中设置想要包括到项目构建中的子项目。在构建的初始化阶段(Initialization),Gradle会根据settings.gradle 文件来判断有哪些子项目被include到了构建中,并为每一个子项目初始化一个Project对象,在构建脚本中通过project(‘:sub-project-name’)来引用子项目对应的Project对象。
通常,多模块项目的目录结构要求将子模块放在父项目的根目录下,但是如果有特殊的目录结构,可以在settings.gradle文件中配置。
我所在的项目包括:
一个描述核心业务的core模块
一个遗留的Enterprise Java Bean(enterprise-beans)模块
两个提供不同服务的Web项目(cis-war和admin-war)
一个通过schema生成jaxb对象的jaxb项目以及一个用来用来打ear包的ear项目
一个用于存放项目配置文件相关的config子目录。它不是子模块,所以 config不应该被加到项目的构建中去。
它们都放置在根项目目录下。我们通过如下的settings.gradle来设置项目中的子项目:
我们将需要加入到项目构建中的子项目配置在settings.gradle文件中,而没有加入不需要的config子目录。
1.2 共享配置
在大型Java项目中,子项目之间必然具有相同的配置项。我们在编写代码时,要追求代码重用和代码整洁;而在编写Gradle脚本时,同样需要保持代码重用和代码整洁。Gradle 提供了不同的方式使不同的项目能够共享配置。
allprojects:allprojects是父Project的一个属性,该属性会返回该Project对象以及其所有子项目。在父项目的build.gradle脚本里,可以通过给allprojects传一个包含配置信息的闭包,来配置所有项目(包括父项目)的共同设置。通常可以在这里配置IDE的插件,group和version等信息,比如:
这样就会给所有的项目(包括当前项目以及其子项目)应用上idea插件。
subprojects:subprojects和allprojects一样,也是父Project的一个属性,该属性会返回所有子项目。在父项目的build.gradle脚本里,给 subprojects传一个包含配置信息的闭包,可以配置所有子项目共有的设置,比如共同的插件、repositories、依赖版本以及依赖配置:
这就会给所有子项目设置上java的插件、使用mavenCentral作为 所有子项目的repository以及对Guava[4]和JUnit的项目依赖。此外,这里还在ext里配置依赖包的版本,方便以后升级依赖的版本。
configure:在项目中,并不是所有的子项目都会具有相同的配置,但是会有部分子项目具有相同的配置,比如在我所在的项目里除了cis-war和admin-war是web项目之外,其他子项目都不是。所以需要给这两个子项目添加war插件。Gradle的configure可以传入子项目数组,并为这些子项目设置相关配置。在我的项目中使用如下的配置:
configure需要传入一个Project对象的数组,通过查找所有项目名包含war的子项目,并为其设置war插件。
1.3 独享配置
在项目中,除了设置共同配置之外, 每个子项目还会有其独有的配置。比如每个子项目具有不同的依赖以及每个子项目特殊的task等。Gradle提供了两种方式来分别为每个子项目设置独有的配置。
在父项目的build.gradle文件中通过project(‘:sub-project-name’)来设置对应的子项目的配置。比如在子项目core需要Hibernate的依赖,可以在父项目的build.gradle文件中添加如下的配置:
注意这里子项目名字前面有一个冒号(:)。 通过这种方式,指定对应的子项目,并对其进行配置。
我们还可以在每个子项目的目录里建立自己的构建脚本。在上例中,可以在子项目core目录下为其建立一个build.gradle文件,并在该构建脚本中配置core子项目所需的所有配置。例如,在该build.gradle文件中添加如下配置:
根据我对Gradle的使用经验,对于子项目少,配置简单的小型项目,推荐使用第一种方式配置,这样就可以把所有的配置信息放在同一个build.gradle文件里。例如我同事郑晔的开源项目moco。它只有两个子项目,因而就使用了第一种方式配置,在项目根目录下的build.gradle文件中设置项目相关的配置信息。但是,若是对于子项目多,并且配置复杂的大型项目,使用第二种方式对项目进行配置会更好。因为,第二种配置方式将各个项目的配置分别放到单独的build.gradle文件中去,可以方便设置和管理每个子项目的配置信息。
1.4 其他共享
在Gradle中,除了上面提到的配置信息共享,还可以共享方法以及Task。可以在根目录的build.gradle文件中添加所有子项目都需要的方法,在子项目的build.gradle文件中调用在父项目build.gradle脚本里定义的方法。例如我定义了这样一个方法,它可以从命令行中获取属性,若没有提供该属性,则使用默认值:
注意,这段脚本完全就是一段Groovy代码,具有非常好的可读性。
由于在父项目中定义了defaultProperty方法,因而在子项目的build.gradle文件中,也可以调用该方法。
Gradle作为新的构建工具,获得了2010 Springy大奖,并入围了2011的Jax最佳Java技术发明奖。它是基于Groovy语言的构建工具,既保持了Maven的优点,又通过使用Groovy定义的DSL[2],克服了 Maven中使用XML繁冗以及不灵活等缺点。在Eugene Dvorkin撰写的文章《最让人激动的5个Java项目》中,他是这样介绍Gradle的:
“工程自动化是软件项目成功的必要条件,而且它应该实现起来简单、易用、好玩。构建没有千篇一律的方法,所以Gradle没有死板的强加方法于我们,尽管你会认为查找和描述方法很重要,然而Gradle对于如何描述有着非常好的支持。我不认为工具能够拯救我们,但是Gradle能给你所需要的自由,你可以利用Gradle构建易描述的、可维护的、简洁的、高性能项目”。
在最近半年里,我在使用Gradle作为构建脚本的大型Java项目上工作,更深切体会到Gradle在项目构建过程中是如此的简单、易用。
1. 多Module的项目
Hibernate项目负责人Steve Ebersole在Hibernate将构建脚本从Maven换成Gradle时,专门写了一篇文章《Gradle: why?》,文中提到Maven的一个缺点就是:Maven不支持多module的构建。在Micro-Service[3]架构风格流行的今天,在一个项目里面包含多个Module已成为一种趋势。Gradle天然支持多module,并且提供了很多手段来简化构建脚本。在Gradle中,一个模块就是它的一个子项目(subproject),所以,我使用父项目来描述顶级项目,使用子项目来描述顶级项目下面的模块。
1.1 配置子项目
在多模块的项目中,Gradle遵循惯例优于配置 (Convention Over Configuration)原则。
在父项目的根目录下寻找settings.gradle文件,在该文件中设置想要包括到项目构建中的子项目。在构建的初始化阶段(Initialization),Gradle会根据settings.gradle 文件来判断有哪些子项目被include到了构建中,并为每一个子项目初始化一个Project对象,在构建脚本中通过project(‘:sub-project-name’)来引用子项目对应的Project对象。
通常,多模块项目的目录结构要求将子模块放在父项目的根目录下,但是如果有特殊的目录结构,可以在settings.gradle文件中配置。
我所在的项目包括:
一个描述核心业务的core模块
一个遗留的Enterprise Java Bean(enterprise-beans)模块
两个提供不同服务的Web项目(cis-war和admin-war)
一个通过schema生成jaxb对象的jaxb项目以及一个用来用来打ear包的ear项目
一个用于存放项目配置文件相关的config子目录。它不是子模块,所以 config不应该被加到项目的构建中去。
它们都放置在根项目目录下。我们通过如下的settings.gradle来设置项目中的子项目:
include 'core', 'enterprise-beans', 'cis-war', 'admin-war', 'jaxb', 'ear'
我们将需要加入到项目构建中的子项目配置在settings.gradle文件中,而没有加入不需要的config子目录。
1.2 共享配置
在大型Java项目中,子项目之间必然具有相同的配置项。我们在编写代码时,要追求代码重用和代码整洁;而在编写Gradle脚本时,同样需要保持代码重用和代码整洁。Gradle 提供了不同的方式使不同的项目能够共享配置。
allprojects:allprojects是父Project的一个属性,该属性会返回该Project对象以及其所有子项目。在父项目的build.gradle脚本里,可以通过给allprojects传一个包含配置信息的闭包,来配置所有项目(包括父项目)的共同设置。通常可以在这里配置IDE的插件,group和version等信息,比如:
allprojects { apply plugin: 'idea' }
这样就会给所有的项目(包括当前项目以及其子项目)应用上idea插件。
subprojects:subprojects和allprojects一样,也是父Project的一个属性,该属性会返回所有子项目。在父项目的build.gradle脚本里,给 subprojects传一个包含配置信息的闭包,可以配置所有子项目共有的设置,比如共同的插件、repositories、依赖版本以及依赖配置:
subprojects { apply plugin: 'java' repositories { mavenCentral() } ext { guavaVersion = ’14.0.1’ junitVersion = ‘4.10’ } dependencies { compile( “com.google.guava:guava:${guavaVersion}” ) testCompile( “junit:junit:${junitVersion}” ) } }
这就会给所有子项目设置上java的插件、使用mavenCentral作为 所有子项目的repository以及对Guava[4]和JUnit的项目依赖。此外,这里还在ext里配置依赖包的版本,方便以后升级依赖的版本。
configure:在项目中,并不是所有的子项目都会具有相同的配置,但是会有部分子项目具有相同的配置,比如在我所在的项目里除了cis-war和admin-war是web项目之外,其他子项目都不是。所以需要给这两个子项目添加war插件。Gradle的configure可以传入子项目数组,并为这些子项目设置相关配置。在我的项目中使用如下的配置:
configure(subprojects.findAll {it.name.contains('war')}) { apply plugin: 'war' }
configure需要传入一个Project对象的数组,通过查找所有项目名包含war的子项目,并为其设置war插件。
1.3 独享配置
在项目中,除了设置共同配置之外, 每个子项目还会有其独有的配置。比如每个子项目具有不同的依赖以及每个子项目特殊的task等。Gradle提供了两种方式来分别为每个子项目设置独有的配置。
在父项目的build.gradle文件中通过project(‘:sub-project-name’)来设置对应的子项目的配置。比如在子项目core需要Hibernate的依赖,可以在父项目的build.gradle文件中添加如下的配置:
project(‘:core’) { ext{ hibernateVersion = ‘4.2.1.Final’ } dependencies { compile “org.hibernate:hibernate-core:${hibernateVersion}” } }
注意这里子项目名字前面有一个冒号(:)。 通过这种方式,指定对应的子项目,并对其进行配置。
我们还可以在每个子项目的目录里建立自己的构建脚本。在上例中,可以在子项目core目录下为其建立一个build.gradle文件,并在该构建脚本中配置core子项目所需的所有配置。例如,在该build.gradle文件中添加如下配置:
ext{ hibernateVersion = ‘4.2.1.Final’ } dependencies { compile “org.hibernate:hibernate-core:${hibernateVersion}” }
根据我对Gradle的使用经验,对于子项目少,配置简单的小型项目,推荐使用第一种方式配置,这样就可以把所有的配置信息放在同一个build.gradle文件里。例如我同事郑晔的开源项目moco。它只有两个子项目,因而就使用了第一种方式配置,在项目根目录下的build.gradle文件中设置项目相关的配置信息。但是,若是对于子项目多,并且配置复杂的大型项目,使用第二种方式对项目进行配置会更好。因为,第二种配置方式将各个项目的配置分别放到单独的build.gradle文件中去,可以方便设置和管理每个子项目的配置信息。
1.4 其他共享
在Gradle中,除了上面提到的配置信息共享,还可以共享方法以及Task。可以在根目录的build.gradle文件中添加所有子项目都需要的方法,在子项目的build.gradle文件中调用在父项目build.gradle脚本里定义的方法。例如我定义了这样一个方法,它可以从命令行中获取属性,若没有提供该属性,则使用默认值:
def defaultProperty(propertyName, defaultValue) { return hasProperty(propertyName) ? project[propertyName] : defaultValue }
注意,这段脚本完全就是一段Groovy代码,具有非常好的可读性。
由于在父项目中定义了defaultProperty方法,因而在子项目的build.gradle文件中,也可以调用该方法。
相关文章推荐
- 简述Gradle在大型Java项目上的应用---环境的配置(二)
- 简述Gradle在大型Java项目上的应用---环境的配置(二)
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- Gradle在大型Java项目上的应用
- 在做一个大型java项目,从现在起记录一些技术应用框架配置,一、svn+apace+权限配置
- DOM在java项目中的实际应用(解析XML)
- 结合Java实现的一个腾讯空间备份器谈谈MVC思想在Swing桌面项目中的应用
- java.util.concurrent 在shorturl项目中的应用
- [转]给开发维护大型项目的Java开发者的建议
- 在java程序项目中如何使用xml配置文件存储信息简述