您的位置:首页 > 其它

Using Maven profiles and resource filtering(针对不同环境启用不同的配置值)

2013-03-06 16:43 701 查看

Using Maven profiles and resource filtering

Posted by Paolo Predonzanion June 23, 2009

Introduction

In this tutorial I'll explain how to deal with multiple deployment environments (such as development and production) from a configuration perspective. Specifically I'll show how environment-specific configurations, such as database connections and resource
contents, can be "managed" in a centralized way by the developer.This tutorial assumes some working knowledge of Maven overlays. The Using Maven overlays to build customized applications tutorial is a good starting point, which
also introduces the Portofino example that we'll expand and refine here.If you're impatient (and a bit of a Maven expert) you can jump to the section "Putting it all together: the pom.xml file", where the techniques described in this tutorial are summarized in a single POM file.

Contents

1 Introduction
2 Definition and purpose
3 Example application
4 The "profiles" section
5 Resource filtering5.1 Some security considerations6 Webapp resource filtering
7 Putting it all together: the pom.xml file
8 Building the target
9 Further readings

Definition and purpose

Maven profiles allow a parametrization of the build process with the purpose of making the target application portable across several deployment environments. A profile is the centralized place where you can define build parameters that apply only to certain
environments but not to others.In our case the database connection details are environment-specific. We'll have a "development" profile customized to the needs of a development environment (webapp and database running on "localhost", e.g., the developer's personal laptop) and a "production"
profile customized to the needs of a production environment (webapp pointing to a certain database server).Also we want the application logo to be different for the two environments.Profiles can be activated automatically, e.g., by detecting a certain operating system, jdk version, etc., but can also be activated manually by the developer during the build process. We'll work with the latter situation.Profiles can be specified in the
pom.xml
file or in a separate
profile.xml
file at the top level of the project structure. They can also be specified in user-specific files, outside the project directory structure. More details can
be found in Maven's official introduction to build profiles.For simplicity in our examples we'll define profiles inside the main
pom.xml
, along with other plugin configurations.

Example application

Throughout this tutorial we'll use the same example application we used in the previous Maven overlays tutorial. Briefly, this is a war-overlay project built
on top of a standard Portofino distribution. The project uses Maven to introduce some basic configuration and customizations.Let's have a look at the files:
$ find .
.
./pom.xml
./src
./src/main
./src/main/resources
./src/main/resources/portofino-custom.properties
./src/main/webapp
./src/main/webapp/mylogo.png
./src/main/webapp/mywebapp.css
./src/main/webapp/WEB-INF

Not much, but enough for our goals. The relevant files are:
pom.xml
: the Maven project file
portofino-custom.properties
: Portofino's configuration file
mylogo.png
: a custom logo image
mywebapp.css
: a custom css stylesheetSo this is our starting point. Let's apply the profiles to it.

The "profiles" section

A "profiles" section in the pom.xml file can contain one or more profile definitions.To define two profiles called "development" and "production" simply enter the following fragment:
<profiles>
<profile>
<id>development</id>
<!-- we'll add more stuff here... -->
</profile>
<profile>
<id>production</id>
<!-- ...and here -->
</profile>
</profiles>

Now we want to associate some parameters to each profile. In our case there will be:four parameters that provide the db connection details to a Portofino application;
one parameter to set the application logo.The fragment for the development environment must be modified as follows:
<profile>
<id>development</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:@127.0.0.1:1521:XE</db.connectionURL>
<db.username>devuser</db.username>
<db.password>devpassword</db.password>
<logo.image>mylogo.png</logo.image>
</properties>
</profile>

Notice the five properties db.driverClass, db.connectionURL, db.username, db.password, and logo.image. You can choose any name for them - there is no particular convention.Also notice that, with the shown values, we intend to connect to an Oracle XE instance running on the local machine.For production, the fragment becomes:
<profile>
<id>production</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:@10.0.1.14:1521:APPS</db.connectionURL>
<db.username>productionuser</db.username>
<db.password>productionpassword</db.password>
<logo.image>production_logo.png</logo.image>
</properties>
</profile>

This profile uses the Oracle driver too, but points to a different database server and instance.All the properties and values we've seen so far are just declared but not used yet. To get something useful out of them, we need to dig into (web) resource filtering, as discussed in the following two sections.

Resource filtering

Resource filtering is about performing an automatic "find & replace" on property files and other classpath resources used in a project. Maven's resources plugin takes care of filtering and must be configured like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
<configuration>
<!-- specify UTF-8, ISO-8859-1 or any other file encoding -->
<encoding>UTF-8</encoding>
</configuration>
</plugin>

Also you must tell the plugin where the resources are located and that filtering must be switched on. These lines also go into the pom.xml:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>

We have set up everything in the pom.xml file. Now let's look at the resources that will actually be filtered.The
portofino-custom.properties
file in
src/main/resources
is just the resource we need. This is Portofino's main configuration
file, containing the database connection details. The original file looked like this:
database.jdbc.driverClass=oracle.jdbc.driver.OracleDriver
database.jdbc.connectionURL=jdbc:oracle:thin:@127.0.0.1:1521:XE
database.jdbc.username=myusername
database.jdbc.password=mypassword

model.application.name=MyWebApp
model.stylesheet=/mywebapp.css

Let's modify it to take advantage of resource filtering:
database.jdbc.driverClass=${db.driverClass}
database.jdbc.connectionURL=${db.connectionURL}
database.jdbc.username=${db.username}
database.jdbc.password=${db.password}

model.application.name=MyWebApp
model.stylesheet=/mywebapp.css

Notice that db.driverClass, db.connectionURL, etc are exactly the properties we've defined in the profiles, wrapped inside the ${...} notation that instructs the resource plugin to perform a substitution of values.

Some security considerations

With the approach we've seen, database connection passwords are stored in
pom.xml
. This file, most likely, will end up in the version control system and shared by a group of people. This may be good or bad from a security perspective.It can be good because the location of the passwords is known and declared upfront. Most version control systems can be configured to grant access to the project files only to the people who really need to work on them. So this approach is structured,
has tool support, and only requires the project team to trust its members.However it can also be bad, if company policies do not allow passwords to be stored in the source files or if the development team and the deployment team must not share knowledge of passwords. In these situations, you may want to investigate "identd"
authentication techniques, which don't require passwords and basically authenticate the connection based on the user (in a unix or windows domain sense) running the application server's process.

Webapp resource filtering

A web application resource is any jsp, html, css, javascript, etc. resources located in the
src/main/webapp
directory of a Maven project. These are different from the resources we discussed in the "Resource filtering" section, which
end up in the
WEB-INF/classes
directory of the WAR file.Many Maven users find this distinction confusing at first, thinking that all resources are of the same type. However, in Maven, webapp resources are treated differently, as explained in the the official
maven-war-plugin documentation.Another way to think about this distinction is classpath resources vs. non-classpath resources. Webapp resources are of the latter type.The maven-war-plugin is responsible for webapp resource filtering. To configure it use the following pom.xml fragment:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<webResources>
<resource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.css</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
</webResources>
</configuration>
</plugin>

Notice that we've set up the plugin to filter .css files.The only interesting webapp resource we have is
src/main/webapp/mywebapp.css
, a stylesheet that looks like this:
@import url("default.css");

div#logo a {
/* some lines omitted */
background: url('mylogo.png') no-repeat 0px 0px;
/* some more lines omitted */
}

Our goal is to parametrize the logo image. Edit the file:
@import url("default.css");

div#logo a {
/* some lines omitted */
background: url('${logo.image}') no-repeat 0px 0px;
/* some more lines omitted */
}

The logo.image property allows the application to point to different logo images depending on the profile that is selected:'mylogo.png' for development
'production_logo.png' for productionOf course make sure you add a 'production_logo.png' to the project.

Putting it all together: the pom.xml file

Putting all the fragments we've discussed in the previous sections we finally get the following 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.example</groupId>
<artifactId>mywebapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>mywebapp Maven Webapp</name>
<url>http://www.example.com</url>

<dependencies>
<!-- The following dependency makes this project a war overlay -->
<dependency>
<groupId>com.manydesigns</groupId>
<artifactId>portofino-war</artifactId>
<version>3.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
<!-- Other dependencies go here -->
</dependencies>

<build>
<finalName>mywebapp</finalName>
<plugins>
<!-- Enabling and configuring regular resources filtering. See also section
"resources" below -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
<configuration>
<!-- specify UTF-8, ISO-8859-1 or any other file encoding -->
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- Enabling and configuring web resources filtering -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<webResources>
<resource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.css</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
<!-- Instructing the resources plugin to filter certain directories -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

<!-- Profiles start here -->
<profiles>
<!-- Development environment @ my laptop -->
<profile>
<id>development</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:@127.0.0.1:1521:XE</db.connectionURL>
<db.username>devuser</db.username>
<db.password>devpassword</db.password>
<logo.image>mylogo.png</logo.image>
</properties>
</profile>
<!-- Production environment @ production server -->
<profile>
<id>production</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:@10.0.1.14:1521:APPS</db.connectionURL>
<db.username>productionuser</db.username>
<db.password>productionpassword</db.password>
<logo.image>production_logo.png</logo.image>
</properties>
</profile>
</profiles>

</project>

Building the target

Ok, we're ready to build. Let's check we have all the files in place.
$ find .
.
./pom.xml
./src
./src/main
./src/main/resources
./src/main/resources/portofino-custom.properties
./src/main/webapp
./src/main/webapp/mylogo.png
./src/main/webapp/mywebapp.css
./src/main/webapp/production_logo.png
./src/main/webapp/WEB-INF

Then run:
mvn package -P development

Make sure you get the "BUILD SUCCESSFUL" message.This runs the target using the development profile (notice the "-P" parameter). Maven creates the WAR archive
target/mywebapp.war
and an expanded version under
target/mywebapp/
.Let's check that resource filtering has actually been applied.
$ cat target/mywebapp/WEB-INF/classes/portofino-custom.properties
database.jdbc.driverClass=oracle.jdbc.driver.OracleDriver
database.jdbc.connectionURL=jdbc:oracle:thin:@127.0.0.1:1521:XE
database.jdbc.username=devuser
database.jdbc.password=devpassword

model.application.name=MyWebApp
model.stylesheet=/mywebapp.css

And:
$ cat target/mywebapp/mywebapp.css
@import url("default.css");

div#logo a {
display: block;
position: absolute;
top: 14px; /* distance from top margin */
left: 20px; /* distance from left margin */
text-decoration: none;
color: black;
font-weight: bold;
font-size: 2em;
background: url('mylogo.png') no-repeat 0px 0px;
padding-top: 60px; /* the logo's height */
height: 0px;
width: 200px; /* the logo's width */
overflow: hidden;
}

The words in bold show the applied substitutions.If you want to build for the production environment you can run:
mvn package -P production

And verify that another set of substitutions have been applied.

Further readings

Maven can be employed in many useful situations. For a real life application see our tutorial Integrating Portofino with Alfresco.说明通过mvn package -P development 指明调用<profiles>中id=development的<profile>,src/main/resources下的
portofino-custom.properties文件配置值从development中取
操作实例:实际操作中,假设maven项目有多个模块parentproj|->basemodule(打jar包)|->bussinessmodule(打jar包,依赖basemodule-version.jar)|->webmodule(打war包,依赖bussinessmodule-version.jar)a).数据的配置文件放在bussinessmodule的src/main/resources下的conf/db.properties中db.properties=========================================test.jdbc.url=${test.jdbc.url}test.jdbc.username=${test.jdbc.username}test.jdbc.password=${test.jdbc.password}b).bussinessmodule模块下的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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion><parent><artifactId>parentproj</artifactId><groupId>com.parentproj</groupId><version>0.0.1</version></parent><groupId>com.parentproj.bussinessmodule</groupId><artifactId>bussinessmodule</artifactId><version>0.0.1</version><packaging>jar</packaging><name>bussinessmodule</name><!-- 不同环境配置 --><profiles><profile><id>development</id><properties><test.jdbc.url>jdbc:oracle:thin:@11.11.13.123:1521:orcl</test.jdbc.url><test.jdbc.username>development</test.jdbc.username><test.jdbc.password>development123</test.jdbc.password></properties></profile><profile><id>product</id><properties><test.jdbc.url>jdbc:oracle:thin:@12.2.0.27:1521:orcl</test.jdbc.url><test.jdbc.username>product</test.jdbc.username><test.jdbc.password>product13245</test.jdbc.password></properties></profile></profiles><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>2.3</version><configuration><encoding>UTF-8</encoding></configuration></plugin></plugins><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></resources></build></project>c).maven命令方式开始 -> 运行 -> cmd ->cd d:\java\workspaces\parentproj -> mvn clean install -Dmaven.test.skip=true -Pdevelopment或mvn clean install -Dmaven.test.skip=true -Pproduct如果以eclipse run as 的方式打包,在配置好Maven Build后,指定Profiles的值为development或product
转自:http://www.manydesigns.com/en/portofino/portofino3/tutorials/using-maven-profiles-and-resource-filtering
其他参考资料:http://archboy.org/2012/05/21/apache-maven-profile-filtering-multiple-build-environments/

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: