Build an executable jar package using Maven-jar and copy dependency

Source: Internet
Author: User

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:

    1. 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.) )
    2. Find all the libraries your project relies on.
    3. 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-pluginCan 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-pluginOne 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:

    1. In a "template" MANIFEST. The MF file defines all of your custom configurations.
    2. 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:treeParameter 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:treeThe 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> &LT;VERSION&GT;1.0-SN                                Apshot</version> <executions> <execution>                                <id>pos</id> <phase>install</phase>                                <goals> <goal>deploy</goal> </goals> <configuration> &LT;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 file

In 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

-PdeploywarTag notification to explicitly include the deploywar configuration file. -Denv=devstatement 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 Plugin

Maven 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:

    1. Create a new project with POM packaging, set to " maven-plugin ".
    2. Includes a maven-plugin-plugin call that can define your advertisement plug-in target.
    3. Create a Maven plugin " mojo " Class (an extended AbstractMojo Class).
    4. The Javadoc of the class are annotated to define the target, and each variable that will be advertised as a configuration parameter is annotated.
    5. 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.java
Package 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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.