Transferred from: http://www.ibm.com/developerworks/cn/java/j-5things13/
Maven is a great build tool for Java™ developers, and you can use it to manage your project lifecycle. As a lifecycle management tool, Maven is phase-based, unlike Ant, which is built on a "task" basis. Maven completes all phases of the project life cycle, including validation, code generation, compilation, testing, packaging, integration testing, installation, deployment, and project site creation and deployment.
To better understand the differences between Maven and traditional build tools, let's look at the process of building a JAR file and an EAR file. With Ant, you might need to define a proprietary task to assemble each artifact. On the other hand, Maven can do most of the work for you: you just have to tell it is a JAR file or an EAR file, and then instruct it to complete the "pack and go" process. Maven will find the required resources and then build the file.
In the Resources section of this article, you'll find a lot of introductory tutorials on Maven. The 5 tips in this article are designed to help you solve some of the problems that will arise when you use Maven to manage the life cycle of your application, the programming scenarios that occur.
1. Executable JAR file
Building a jar file using Maven is easier: simply define the project as "Jar" and then execute the wrapper life cycle phase. But it is cumbersome to define an executable JAR file. Take the following steps to be more efficient:
- The MANIFEST of the JAR in which you define the executable class. A class is defined in the MF file
main
. (MANIFEST.MF is what Maven generates when you wrap your application.) )
- Find all the libraries your project relies on.
- In your MANIFEST. The MF file contains those libraries that are easy for your application to find.
You can do this manually, or if you want to be more efficient, you can use two Maven plugins to help you complete: maven-jar-plugin
and maven-dependency-plugin
.
Maven-jar-plugin
maven-jar-plugin
Can do a lot of things, but here we only use it to modify the default MANIFEST. The contents of the MF file are interesting. Add the code shown in Listing 1 in the plug-in section of your POM file:
Listing 1. Use Maven-jar-plugin to modify the MANIFEST. Mf
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> maven-jar-plugin</artifactid> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> < mainclass>com.mypackage.myclass</mainclass> </manifest> </archive> </ Configuration> </plugin>
All Maven plugins <configuration>
publish their configuration through an element, in this case, maven-jar-plugin
modify its properties, especially the properties of the archive
archive file manifest
, which controls MANIFEST. The contents of the MF file. Consists of 3 elements:
addClassPath
: Set this element to true to tell you maven-jar-plugin
to add an Class-Path
element to MANIFEST. MF file, and Class-Path
include all dependencies in the element.
classpathPrefix
: If you plan to include all of your dependencies in the same directory as the jar you will build, you can ignore it, otherwise use classpathPrefix
to specify a prefix for all dependent JAR files. In Listing 1, it is classpathPrefix
noted that all dependencies should be in the folder relative to the archive file lib
.
mainClass
: lib
Use this element to define the class name that will be executed when the user executes the JAR file using a command.
Maven-dependency-plugin
When you use these 3 elements to configure the MANIFEST. MF file, the next step is to copy all dependencies to the lib
folder. To do this, use maven-dependency-plugin
, as shown in Listing 2:
Listing 2. To copy a dependency to a library using Maven-dependency-plugin
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>install< /phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputdirect Ory> ${project.build.directory}/lib </outputDirectory> </configuration> </execution> </executions> </plugin>
maven-dependency-plugin
One copy-dependencies
, the goal is to copy your dependencies to the directory of your choice. In this case, I copied the dependencies to build
the directory under Directories lib
( project-home/target/lib
).
Place your dependencies and modify the MANIFEST. After the MF is in place, you can start the application with a simple command:
Java-jar Jarfilename.jar
Back to top of page
2. Custom MANIFEST. Mf
While maven-jar-plugin
allowing you to modify MANIFEST.MF
the common parts of a file, sometimes you need a more personalized MANIFEST. Mf. The solution is twofold:
- In a "template" MANIFEST. The MF file defines all of your custom configurations.
- Configuration
maven-jar-plugin
to use your MANIFEST. MF file, and then use some Maven configuration enhancements.
For example, consider a JAR file that contains a Java proxy. To run a Java proxy, you need to define Premain-Class
and set a license. Listing 3 shows such a MANIFEST. The contents of the MF file:
Listing 3. In a custom-made MANIFEST. MF file defined in Premain-class
Manifest-version:1.0premain-class:com.geekcap.openapm.jvm.agent.agentcan-redefine-classes: Truecan-retransform-classes:truecan-set-native-method-prefix:true
In Listing 3, I have specified Premain-Class
- com.geekcap.openapm.jvm.agent.Agent
the license to redefine and re-convert a class. Next, I update the maven-jar-plugin
code to include MANIFEST. MF file. As shown in Listing 4:
Listing 4. Contains Premain-class
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> maven-jar-plugin</artifactid> <configuration> <archive> <manifestFile> Src/main/resources/meta-inf/manifest. MF </manifestFile> <manifest> <addClasspath>true</addClasspath> < classpathprefix>lib/</classpathprefix> <mainClass> Com.geekcap.openapm.ui.PerformanceAnalyzer </mainClass> </manifest> </archive > </configuration> </plugin>
Maven 3
Maven 2 has established its position as one of the most popular and easy-to-use open source Java lifecycle management tools. Maven 3, upgraded to Alpha 5 in September 2010, brings some long-awaited improvements. Find the new features of Maven in the Resources section.
This is an interesting example because it defines both a Premain-Class
-allow JAR file to run as a Java agent, and one mainClass
-to allow it to run as an executable jar file. In this particular case, I used OpenAPM
(a code-tracking tool I've built) to define the code tracking that will be logged by the Java Proxy and a user interface. In short, this example shows the power of an explicit manifest file combined with dynamic modification.
Back to top of page
3. Reliance on item tree
One of the most useful features of MAVEN is that it supports dependency management: You only need to define the libraries your application relies on, Maven finds them, downloads them, and then uses them to compile your code.
When necessary, you need to know the source of the specific dependencies-so that you can find differences and inconsistencies between different versions of the same JAR file. In this case, you will need to prevent a version of the jar file from being included in your build, but first you need to locate the dependency that holds the jar.
Once you know the following commands, locating the dependencies is often fairly easy:
MVN Dependency:tree
dependency:tree
Parameter displays all of your direct dependencies, and then displays all child dependencies (along with their child dependencies, and so on). For example, listing 5 extracts the client libraries needed for a dependency of the ego:
Listing 5. Maven relies on item tree
[info]------------------------------------------------------------------------[INFO] Building Client Library for communicating with the lde[info] task-segment: [Dependency:tree][info]-------------------- ----------------------------------------------------[INFO] [dependency:tree {execution:default-cli}][info] Com.lmt.pos:sis-client:jar:2.1.14[info] +-Org.codehaus.woodstox:woodstox-core-lgpl:jar:4.0.7:compile[info] | \-Org.codehaus.woodstox:stax2-api:jar:3.0.1:compile[info] +-org.easymock:easymockclassextension:jar:2.5.2:test[ INFO] | +-Cglib:cglib-nodep:jar:2.2:test[info] | \-org.objenesis:objenesis:jar:1.2:test
In Listing 5 you can see the sis-client
project needs woodstox-core-lgpl
and easymockclassextension
libraries. Libraries easymockclassextension
, in turn, require libraries cglib-nodep
and objenesis
libraries. If I objenesis
have a problem, such as two versions, 1.2 and 1.3, then this dependent item tree may show me that the 1.2 artifacts are imported directly from easymockclassextension
the library.
dependency:tree
The parameters save me a lot of debugging time, and I hope it will help you as well.
Back to top of page
4. Using the configuration file
Most major projects have at least one core environment, consisting of development-related tasks, quality assurance (QA), integration, and production. The challenge of managing all these environments is to configure your build, which must be connected to the correct database, execute the correct set of scripts, and deploy the correct artifacts for each environment. Using Maven profiles allows you to accomplish these tasks without having to establish explicit directives for each environment individually.
The key is the merging of the environment profile and the task-oriented configuration file. Each environment profile defines its specific location, script, and server. So, in my pox.xml file, I'll define the task-oriented configuration file " deploywar
", as shown in Listing 6:
Listing 6. Deployment configuration file
<profiles> <profile> <id>deploywar</id> <build> <plugins> <plugin> <groupId>net.fpic</groupId> <artifactId>tomcat-deployer-plugin</artifactId> <VERSION>1.0-SN Apshot</version> <executions> <execution> <id>pos</id> <phase>install</phase> <goals> <goal>deploy</goal> </goals> <configuration> <HOST&G T;${deploymentmanagerresthost}This configuration file (which is distinguished by the ID " deploywar
") tomcat-deployer-plugin
is configured to connect to a specific host and port, as well as to specify the user name and password certificate. All this information is defined using variables, such as ${deploymentmanagerRestHost}
. These variables are defined in my Profiles.xml file, as shown in Listing 7:
Listing 7. Profiles.xml <!--defines the development deployment information--<profile> <id>dev</ id> <activation> <property> <name>env</name> <value>dev</value> </property> </activation> &L T;properties> <deploymentManagerRestHost>10.50.50.52</deploymentManagerRestHost> <deploymentManagerRestPort>58090</deploymentManagerRestPort> <deploymentmanagerrestusern Ame>myusername</deploymentmanagerrestusername> <deploymentManagerRestPassword>mypassword< /deploymentmanagerrestpassword> </properties> </profile> <!--defines the QA de Ployment Information-<profile> <id>qa</id> <activation> <property> <name>env</name> <value>qa</value> </property> </activation> <properties> <deploymentmanagerresthost>10.50.50.50</deployme Ntmanagerresthost> <deploymentManagerRestPort>58090</deploymentManagerRestPort> <deploymentManagerRestUsername> Myotherusername </deploymentmanagerrestusernam e> <deploymentManagerRestPassword> Myotherpassword </deployment Managerrestpassword> </properties> </profile>
Deploying the Maven configuration fileIn the Profiles.xml file in Listing 7, I defined two configuration files and activated them based on env
the values of the (environment) properties. If the env
property is set to dev
, the development deployment information is used. If the env
property is set to qa
, then the QA deployment information is used, and so on.
Here is the command to deploy the file:
Mvn-pdeploywar-denv=dev clean Install
-Pdeploywar
Tag notification to explicitly include the deploywar
configuration file. -Denv=dev
statement to create a env
system property named and set its value to dev
, which activates the development configuration. Delivery -Denv=qa
activates the QA configuration.
Back to top of page
5. Customizing the Maven PluginMaven has more than 10 pre-built plugins for you to use, but sometimes you just want to find the plug-in you need, and it's easier to build a custom Maven plugin:
- Create a new project with POM packaging, set to "
maven-plugin
".
- Includes a
maven-plugin-plugin
call that can define your advertisement plug-in target.
- Create a Maven plugin "
mojo
" Class (an extended AbstractMojo
Class).
- The Javadoc of the class are annotated to define the target, and each variable that will be advertised as a configuration parameter is annotated.
- Implement a
execute()
method that calls your plug-in that will be called.
For example, listing 8 shows the relevant parts of a custom plug-in for deploying TOMCAT:
Listing 8. Tomcatdeployermojo.javaPackage Net.fpic.maven.plugins;import Java.io.file;import Java.util.stringtokenizer;import Net.fpic.tomcatservice64.tomcatdeploymentserverclient;import Org.apache.maven.plugin.abstractmojo;import Org.apache.maven.plugin.mojoexecutionexception;import Com.javasrc.server.embedded.commandrequest;import Com.javasrc.server.embedded.commandresponse;import Com.javasrc.server.embedded.credentials.credentials;import Com.javasrc.server.embedded.credentials.usernamepasswordcredentials;import com.javasrc.util.fileutils;/** * Goal That deploys a Web application to Tomcat * * @goal Deploy * @phase Install */public class Tomcatdeployermojo extends Abstr actmojo{/** * The host name or IP address of the deployment server * * @parameter alias= "host" expression= "${deploy.host} "@required */private String serverhost;/** * The port of the deployment server * * @parameter alias=" port "expression=" $ {Deploy.port} "default-value=" 58020 "*/private String serverport;/** * The username to connect to the DeploymenT Manager (if omitted then the plugin * attempts-to-deploy the application to the server without credentials) * * @parame ter alias= "username" expression= "${deploy.username}" */private String username;/** * The password for the specified Userna Me * * @parameter alias= "password" expression= "${deploy.password}" */private String password;/** * The name of the source Artifact to deploy, such as Target/pos.war * * @parameter alias= "Artifactsource" Expression=${deploy.artifactsource} "* @required */private String artifactsource;/** * The destination name of the artifact to deploy, such as Root.war. * If not present then the * artifact Source name is used (without pathing information) * * @parameter alias= "artifactdest Ination "* expression=${deploy.artifactdestination}" */private String artifactdestination; public void execute () throws Mojoexecutionexception {GetLog (). info ("Server Host:" + ServerHost + ", Se RVer Port: "+ ServerPort +", Artifact sourCE: "+ artifactsource +", Artifact Destination: "+ artifactdestination); Validate our fields if (ServerHost = = null) {throw new Mojoexecutionexception ("No Deployment host SPE Cified, deployment is not possible "); } if (Artifactsource = = null) {throw new Mojoexecutionexception ("No source artifact is specified, deploy ment is not possible "); } ... }}
In the head of this class, the @goal
annotation specifies the target to be executed by the MOJO, and @phase
indicates the stage of the target execution. In addition to an expression that maps to a system property that has a real value, each advertised attribute has a @phase
comment that specifies the alias by the parameter being executed. If the attribute has a @required
comment, it is required. If it has one default-value
, then this value will be used if it is not specified. In the execute()
method, you can call getLog()
to access the Maven logger, which, depending on the record level, outputs a specific message to the standard output device. If the plug-in fails, throwing one MojoExecutionException
will cause the build to fail.
Build an executable jar package using Maven-jar and copy dependency