2008年12月27日星期六

使用maven2构建多环境

这种解决办法有别于maven的官方解决方法。


软件的开发,一般有3个环境:开发(dev)、测试(test)、生产(live)。
dev:开发人员在本机上开发,如也许数据库是本机上,log的级别一般在DEBUG;
test:测试专用,完成构建工作,有专门的测试的库(不允许使用生产环境的库),log级别一般在INFO;
live:实际部署的环境。

每种环境有作一些差异,尤其对于dev来说,每个开发人员环境差异就更大,所以每个开发人员都可以配置自己独特的环境。在每种环境下只需要针对该环境配置一次即可,不需要在每次环境切换时修改配置。

这种情况下,使用maven很容易解决上述问题。文字描述比较难懂,还是例子来说话。

下面的工作前提是安装好maven2。在某目录下创建2个工程,这里只是例子组织名以及工程名根据自己喜好设置:
  • mvn archetype:create -DgroupId=com.kiwiyard.shamrock -DartifactId=shamrock-namenode-dal
工程名:shamrock-namenode-dal,后面简称为dal
创建好工程,即创建一个同工程名的目录,所有工程信息都在此目录下,
并自动创建好java的package:com.kiwiyard.shamrock
  • mvn archetype:create -DgroupId=com.kiwiyard.shamrock -DartifactId=shamrock-namenode-service
创建一个shamrock-namenode-service工程,简称为service。

再在此目录下创建一个pom.xml和一个和该项目相关的环境配置文件shamrock.properties(文件名可自己随意取),后面会用到。一切完成后目录的结构如下:

|--shamrock.properties
|--pom.xml
|--shamrock-namenode-dal
****|--pom.xml
|--shamrock-namenode-service
****|--pom.xml

需要说明的是service依赖dal,service和dal都继承一个父pom,就是顶层的pom.xml。

  • 父pom.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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kiwiyard.shamrock</groupId>
<artifactId>shamrock</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

<modules>
<module>shamrock-namenode-dal</module>
<module>shamrock-namenode-service</module>
</modules>

</project>


分别到dal和service目录下,创建目录src/main/resources和src/test/resources。到dal的src/main/resources/下创建一个数据库文件datasource.properties,因为在dal里需要访问数据库,这正是我们需要对不同情况处理的。

分别在dal和service的
src/main/resources和src/test/resources下创建log4j.properties的日志配置文件。
  • dal的pom.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">

<parent>
<groupId>com.kiwiyard.shamrock</groupId>
<artifactId>shamrock</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>shamrock-namenode-dal</artifactId>
<packaging>jar</packaging>
<name>shamrock-namenode-dal</name>
<url>http://www.kiwiyard.com</url>

<dependencies>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
<scope>run</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>run</scope>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.13</version>
<scope>run</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<directory>${basedir}</directory>
<filters>
<filter>../shamrock.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

</project>

注意这里的
<directory>${basedir}</directory>
若不加这个配置,很难指向上级目录里的文件,maven对下面的解析就行不通:
<filter>../shamrock.properties</filter>
就解析成:dal工程所在的目录/../shamrock.properties,这个解析有点傻,当然就无法识别。加上上面的配置就可以了,不会出现上面情况。 就这个问题害的我花了不少时间。
  • service的pom.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">

<parent>
<groupId>com.kiwiyard.shamrock</groupId>
<artifactId>shamrock</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>shamrock-namenode-service</artifactId>
<packaging>jar</packaging>
<name>shamrock-namenode-service</name>
<url>http://www.kiwiyard.com</url>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.kiwiyard.shamrock</groupId>
<artifactId>shamrock-namenode-dal</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.13</version>
<scope>run</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<directory>${basedir}</directory>
<filters>
<filter>../shamrock.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

</project>

dal和service的log4j.properties配置内容如下:
log4j.rootCategory=${log4j.level}, stdout
log4j.appender.stdout=${log4j.appender}
log4j.appender.stdout.layout=${log4j.layout}
log4j.appender.stdout.layout.ConversionPattern=${log4j.pattern}

dal的datasource.properties(其实也可以是其它类型的文件如spring的datasource配置文件)。内容如下:
username = ${db.name}
password = ${db.password}
url = ${db.url}
driverClassName = ${db.driver}
#connectionProperties
defaultAutoCommit = true
#defaultReadOnly
#defaultTransactionIsolation
#defaultCatalog
initialSize = ${db.initialSize}
maxActive = ${db.maxActive}
maxIdle = ${db.maxIdle}
minIdle = ${db.minIdle}
maxWait = ${db.maxWait}
#validationQuery
#testOnBorrow
#testOnReturn
#testWhileIdle
#timeBetweenEvictionRunsMillis
#numTestsPerEvictionRun
#minEvictableIdleTimeMillis
poolPreparedStatements = true
maxOpenPreparedStatements = 0

在这里的log4j和datasource的配置是关键,对于${}符号就是变量,是在不同的环境需要替换成和环境匹配的值。这些匹配的值就需要根据每种环境配置,配置文件为
shamrock.properties,内容如下:
#日志配置================================================
log4j.level = DEBUG
log4j.appender = org.apache.log4j.ConsoleAppender
log4j.layout = org.apache.log4j.PatternLayout
log4j.pattern = %5p %c{2}- %m%n

#数据库配置================================================
db.name = 用户名
db.password = 密码
db.url = jdbc:mysql://dev.kiwiyard.com:3306/shamrock?useUnicode=true&characterEncoding=ut8
db.driver = com.mysql.jdbc.Driver
db.initialSize = 2
db.maxActive = 10
db.maxIdle = 8
db.minIdle = 2
db.maxWait = 2

这里配置的就是环境变量,在编译时就根据这些值替换数据库配置和log4j配置。

项目工程的根目录下(就是顶极pom.xml存在的目录下)
#>mvn resources:resources
再到dal和service
工程的target/classes下,看看其datasource.properties和log4j.properties的内容已经被替换。


例子好像很长,
其实就是几个配置文件里一些关键参数需要替换,配置的关键地方用粗题标出。只要你对maven2有一点了解,理解起来就不是难题。这种实现方式个人觉得比官方的对同一文件创建多个针对环境的版本要好,如按官方办法datasource可能就有datasource.dev、datasource.test、datasource.live这么几个文件,显得很罗嗦。

还有若把你的工程放入svn中(99%是这样),最好不要把和环境相关的信息提交到svn上,如开发者A把自己的提交后,开发者B拿到后很可能要修改才能使用,这些配置之适合特定的个体,不要分发出去。如下是一种解决办法,把指向环境配置文件shamrock.properties(以此为例),改为.shamrock.properties(注意文件名前加了一个点)。
<filter>../shamrock.properties</filter>
=>
<filter>../.shamrock.properties</filter>
shamrock.properties是受svn版本控制的,他代表一些配置的共性,也可能是由项目主管提交的一份参考配置。

其它开发人员拿到shamrock.properties后,cp
shamrock.properties .shamrock.properties,自己所有的配置就可以在.shamrock.properties上改动,不用把该文件提交到svn上,所有人的环境配置都在本地,不会找成混乱


官方的另外一种方式,你可以参考对照2种方式:
http://maven.apache.org/guides/mini/guide-building-for-different-environments.html

没有评论: