这一节我们介绍 Maven 的 Web 项目使用 war 插件针对不同环境打包。这是我在 BAE 部署自己的博客应用的时候整理的一种方案,供大家参考。

最最重要的思路其实就一条:打包之前替换配置文件,从手动变为自动。重点内容

需求的提出:

在开发阶段,我们的 MySQL 数据库连接配置基本上都连着本机数据库, Lucene 索引存放目录基本上是开发者本机的一个目录。但是到了生产环境部署的时候, MySQL 数据库的连接配置和 Lucene 索引存放目录就是另外一个配置了。
那么,我们在打包到生产环境之前是不是要手动将这些配置替换一下呢?
如果手动这样做的话,就显得不灵活,很笨拙了。
好在 Maven 这项工具早就帮我们想到了这个问题。下面我就介绍一下,我在自己的项目 Blog 中是如何操作的。

思路分析:

1、自己的项目里只要是有配置的地方,不要写死在源代码目录(src/main/java)中,而要将配置的信息写在资源目录中 (src/main/resources);
2、即使是写在资源目录中的代码,也尽量将特殊化的配置信息写在配置文件中,这样做的好处有以下两点:
(1)配置信息一般是比较重要的,尤其是生产环境中的配置信息,现在很多代码开源了以后,开发者如果将配置信息提交到 Git 仓库中,很有可能造成一些安全隐患(服务器的连接参数都暴露了,你说能安全吗?),所以一般情况下,这些重要的服务器配置文件应该被 Git 排除掉;
(2)分离出配置信息成为单独的配置文件也方便开发者进行单独管理。
这样开发者将代码开源以后即使不给出配置文件的代码,其他学习者拿到项目以后仍然可以根据 ${db.username} 这样的代码填写出自己本地的配置信息。

即:我们不建议这么做。

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="jdbc:mysql://localhost:3306/db_blog?useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

应该这样做:

<context:property-placeholder location="classpath:config/jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.username}"/>
    <property name="password" value="${db.password}"/>
</bean>

在 config/jdbc.properties 文件中写:

db.url=jdbc:mysql://localhost:3306/db_blog?useUnicode=true&amp;characterEncoding=UTF-8
db.username=root
db.password=123456

3、在资源目录下建立不同环境的文件夹,有几个环境,就应该建立几个文件夹;

这里写图片描述

4、使用 Maven 的 war 插件,使用命令指定打包参数,在打包之前替换那些重要的配置文件,就可以针对不同的环境打出适合这些环境的 war 包了。

具体配置代码分析

1、声明主资源目录

<!-- 主资源目录 -->
<resources>
    <resource>
        <!-- 设置主资源目录 -->
        <directory>src/main/resources</directory>
        <!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,是否对主资源目录开启资源过滤 -->
        <filtering>true</filtering>
        <!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,只处理如下配置中包含的资源类型 -->
        <!-- 包括文件 -->
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,不处理如下配置中包含的资源类型(剔除下如下配置中包含的资源类型)-->
        <!-- 排除文件,这些文件打包的时候应该被排除 -->
        <excludes>
            <exclude>config/local/*.properties</exclude>
            <exclude>config/product/*.properties</exclude>
        </excludes>
    </resource>
</resources>

2、声明 profile

<profiles>
    <profile>
        <id>local</id>
        <properties>
            <package.environment>local</package.environment>
        </properties>
        <activation>
            <!-- 默认激活这个配置 -->
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <!-- 生产环境,这里指的是我的 百度云 BAE 环境 -->
        <id>product</id>
        <properties>
            <package.environment>product</package.environment>
        </properties>
    </profile>
</profiles>

特别说明:profile 中的 id,自定义的环境变量 package.environment 的值,和“思路分析3”中建立的不同环境配置文件存放的目录名称应该是一致的,这也叫约定大于配置,这样的约定就可以少配置很多东西了。

3、声明 war 插件

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <archive>
            <addMavenDescriptor>false</addMavenDescriptor>
        </archive>
        <!-- 部署在百度云 bae 上,一定要叫 ROOT.war -->
        <!-- 虽然 IDEA 工具报提示警告,但是可以不理会,不影响使用 -->
        <warName>ROOT</warName>
        <webResources>
            <resource>
                <directory>src/main/resources/config/${package.environment}</directory>
                <targetPath>WEB-INF/classes/config</targetPath>
                <filtering>true</filtering>
            </resource>
        </webResources>
    </configuration>
</plugin>

说明:
warName :指定了打好包的名字;
webResources 下 resource 下 directory :配置真正使用的资源文件存放的位置,通常这个位置不是一个标准 Web 项目应该存放资源文件的位置;
webResources 下 resource 下 targetPath:将上一步 directory 中配置的文件目录下的文件都拷贝到这个目录下;‘
webResources 下 resource 下 filtering:开启打包之前将 directory 下的文件拷贝(覆盖)到 targetPath 下这种配置。

4、介绍运行命令

(1)本地测试
因为我是用 Jertty 插件,本地配置都是本地开发环境的配置,所以可以直接使用

mvn jetty:run

启动 Jetty 服务器。
附:Jetty 插件配置

<!-- Jetty 插件:在本地部署测试更加方便 -->
<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <configuration>
        <httpConnector>
            <port>8080</port>
        </httpConnector>
    </configuration>
</plugin>

(2)打本地环境的包

mvn package -DskipTests

因为我在 profile 的 id 为 local 的配置下写了

<activation>
    <!-- 默认激活这个配置 -->
    <activeByDefault>true</activeByDefault>
</activation>

所以使用 mvn package -DskipTests 不指定 profile 就默认打出的是本地开发环境的 war 包。
(3)打生产环境的包

mvn clean package -DskipTests -Pproduct

说明:通过 -P 指定 profile。

参考资料:
Apache Maven WAR Plugin – Usage http://maven.apache.org/plugins/maven-war-plugin/usage.html
利用maven中resources插件的copy-resources目标进行资源copy和过滤 - - ITeye技术网站 http://xigua366.iteye.com/blog/2080668
Maven根据不同环境打包不同配置文件 - li295214001的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/li295214001/article/details/52044800
介绍maven的作用、核心概念(Pom、Repositories、Artifact、Goal)、用法、常用参数和命令以及简单故障排除、扩展及配置 Maven根据不同个环境打包, 获取不同的配置文件等等 - cheng222e的个人页面 - 开源中国社区 http://my.oschina.net/vernon/blog/271970

Logo

更多推荐