Using Maven profiles and resource filtering(针对不同环境启用不同的配置值)
2013-03-06 16:43
701 查看
Using Maven profiles and resource filtering
Posted by Paolo Predonzanion June 23, 2009Introduction
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 resourcecontents, 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 Introduction2 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 certainenvironments 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.xmlfile or in a separate
profile.xmlfile 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 builton 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.propertiesfile in
src/main/resourcesis 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 inpom.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 thesrc/main/webappdirectory of a Maven project. These are different from the resources we discussed in the "Resource filtering" section, which
end up in the
WEB-INF/classesdirectory 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.warand 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/
相关文章推荐
- maven集成eclipse根据resources profiles filtering进行不同环境打包部署
- Maven 使用profiles filters resources build 打包不同配置开发环境及打包
- maven 的profile 、resource标签应用。不同的环境下编译导入不同配置文件
- ssm中maven中profiles多环境配置
- 通过Maven配置测试环境和开发环境连接不同的数据库
- spring.profiles.active 针对多种启动环境的spring配置
- Maven 的 Web 项目使用 war 插件针对不同环境打包
- Maven_如何为开发和生产环境建立不同的配置文件 --我的简洁方案
- 利用maven的resources、filter和profile实现不同环境使用不同配置文件
- Maven——profile介绍(不同环境配置不同的参数)
- 利用maven按环境打包SpringBoot的不同配置文件
- Maven根据不同个环境打包, 获取不同的配置文件等等
- Maven——profile介绍 (不同环境配置不同的参数)
- 通过Maven配置测试环境和开发环境连接不同的数据库
- Maven项目中通过profile定义使不同环境使用不同配置信息
- Maven根据Profile读取不同配置环境配置文件
- 通过Maven配置测试环境和开发环境连接不同的数据库
- Maven根据不同环境打包不同配置文件
- 通过Maven配置测试环境和开发环境连接不同的数据库
- 使用maven的profile构建不同环境配置