`
aaronjiu_00
  • 浏览: 67817 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于创建可执行的jar文件

阅读更多

上周四下午,放翁同学在TOP群中问了这样一个小问题,聊天记录摘录如下:

有同学知道如何用maven来将第三方jar的代码也打入到生成的项目jar中?就好比eclipse可以直接将部分依赖打入到项目jar中

一看到打包,对于jar类型的项目,运行mvn package,就等同于运行mvn jar:jar,那放翁同学的问题,一定是与jar插件有关了,在Maven官方网站,查阅了一下jar插件的相关文档,未果。

 

临近下班时,我找放翁同学当面了解了一下他真正的需求,就是把该项目的依赖的源码都打入到一个可执行的jar包中,我看了看Maven官方网站的插件列表,以前对assembly插件有点印象,这个插件或许可以胜任放翁的需求,就直接告诉他,试试这个插件吧,第二天早上上班过来,一问放翁,这个东东确实管用,解决了放翁同学的问题。

 

我以前看过这个插件的文档,但自己却没有使用过,自己也动手Demo一下,和大家分享一下吧

  1. 创建一个jar项目
    tonglin@tonglin-desktop:~$ mvn archetype:generate
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'archetype'.
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Maven Default Project
    [INFO]    task-segment: [archetype:generate] (aggregator-style)
    [INFO] ------------------------------------------------------------------------
    [INFO] Preparing archetype:generate
    [INFO] No goals needed for project - skipping
    [INFO] Setting property: classpath.resource.loader.class =>  'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
    [INFO] Setting property: velocimacro.messages.on => 'false'.
    [INFO] Setting property: resource.loader => 'classpath'.
    [INFO] Setting property: resource.manager.logwhenfound => 'false'.
    [INFO] [archetype:generate]
    [INFO] Generating project in Interactive mode
    [INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
    Choose archetype:
    ......
    15: internal -> maven-archetype-quickstart ()
    ......
    Choose a number:  (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41) 15: :
    Define value for groupId: : com.taobao.top.appstore
    Define value for artifactId: : maven-test
    Define value for version:  1.0-SNAPSHOT: :
    Define value for package:  com.taobao.top.appstore: :
    Confirm properties configuration:
    groupId: com.taobao.top.appstore
    artifactId: maven-test
    version: 1.0-SNAPSHOT
    package: com.taobao.top.appstore
     Y: :
    [INFO] ----------------------------------------------------------------------------
    [INFO] Using following parameters for creating OldArchetype: maven-archetype-quickstart:RELEASE
    [INFO] ----------------------------------------------------------------------------
    [INFO] Parameter: groupId, Value: com.taobao.top.appstore
    [INFO] Parameter: packageName, Value: com.taobao.top.appstore
    [INFO] Parameter: package, Value: com.taobao.top.appstore
    [INFO] Parameter: artifactId, Value: maven-test
    [INFO] Parameter: basedir, Value: /home/tonglin
    [INFO] Parameter: version, Value: 1.0-SNAPSHOT
    [INFO] ********************* End of debug info from resources from generated POM ***********************
    [INFO] OldArchetype created in dir: /home/tonglin/maven-test
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 1 minute 27 seconds
    [INFO] Finished at: Tue Dec 22 11:33:19 CST 2009
    [INFO] Final Memory: 8M/14M
    [INFO] ------------------------------------------------------------------------
     

    通过archetype插件的交互操作,我们创建了一个jar项目,名字叫做maven-test
    该原型默认会创建一个包含main函数的类,com.taobao.top.appstore.App,源代码如下:

    package com.taobao.top.appstore;
    
    /**
     * Hello world!
     *
     */
    public class App
    {
        public static void main( String[] args )
        {
            System.out.println( "Hello World!" );
        }
    }
     

    这个类很简单,如果我们想生成可执行的jar文件,需要修改MENIFEST文件,这里我们需要配置jar插件,编辑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">
    	......
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-jar-plugin</artifactId>
    				<configuration>
    					<archive>
    						<manifest>
    							<mainClass>com.taobao.top.appstore.App</mainClass>
    						</manifest>
    					</archive>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    	......
    </project>
     
  2. 打包,创建可执行的jar文件
    tonglin@tonglin-desktop:~/maven-test$ mvn package
     

    查看jar文件的MENIFEST文件内容:

    Manifest-Version: 1.0
    Archiver-Version: Plexus Archiver
    Created-By: Apache Maven
    Built-By: tonglin
    Build-Jdk: 1.6.0_16
    Main-Class: com.taobao.top.appstore.App
     
  3. 运行
    tonglin@tonglin-desktop:~/maven-test$ java -jar target/maven-test-1.0-SNAPSHOT.jar
    Hello World!

    运行成功,这个类很简单,没有任何依赖,如果我们想做些更复杂的东西,首先我们需要

  4. 增加依赖
    <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">
    	......
    	<dependencies>
                    ......
    		<dependency>
    			<groupId>commons-lang</groupId>
    			<artifactId>commons-lang</artifactId>
    			<version>2.1</version>
    		</dependency>
    		......
    	</dependencies>
            ......
    </project> 
  5. 生成Eclipse文件
    tonglin@tonglin-desktop:~$ cd maven-test/
    tonglin@tonglin-desktop:~/maven-test$ mvn eclipse:clean eclipse:eclipse
     
  6. 打开Eclipse,编辑com.taobao.top.appstore.App
    package com.taobao.top.appstore;
    
    import org.apache.commons.lang.StringUtils;
    
    /**
     * Hello world!
     *
     */
    public class App
    {
        public static void main( String[] args )
        {
            final String x = StringUtils.center("Hello World!", 20);
    	System.out.println( x );
        }
    }
     
  7. 再次打包,运行
    tonglin@tonglin-desktop:~/maven-test$ mvn package
    tonglin@tonglin-desktop:~/maven-test$ java -jar target/maven-test-1.0-SNAPSHOT.jar
    Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang/StringUtils
    	at com.taobao.top.appstore.App.main(App.java:13)
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.StringUtils
    	at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    	... 1 more
     

    运行失败,抛出异常说org.apache.commons.lang.StringUtils类找不到,我们需要将org.apache.commons.lang.StringUtils,添加到类路径,修改pom.xml

  8. 添加类路径
    <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">
    	......
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-jar-plugin</artifactId>
    				<configuration>
    					<archive>
    						<manifest>
    							<addClasspath>true</addClasspath>
    							<mainClass>com.taobao.top.appstore.App</mainClass>
    						</manifest>
    					</archive>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    	......
    </project>
     
  9. 再次打包
    tonglin@tonglin-desktop:~/maven-test$ mvn package 

    查看jar包的MENIFEST

    Manifest-Version: 1.0
    Archiver-Version: Plexus Archiver
    Created-By: Apache Maven
    Built-By: tonglin
    Build-Jdk: 1.6.0_16
    Main-Class: com.taobao.top.appstore.App
    Class-Path: commons-lang-2.1.jar
     
  10. 运行
    tonglin@tonglin-desktop:~/maven-test$ java \-jar target/maven-test-1.0-SNAPSHOT.jar
    Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang/StringUtils
    at com.taobao.top.appstore.App.main(App.java:13)
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.StringUtils
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
    ... 1 more 

    运行仍旧失败,那如何把依赖的源代码也打到这个jar包中呢,这个时候,maven-assembly-plugin插件就派上用场了

  11. 配置maven-assembly-plugin
    <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">
    	......
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-jar-plugin</artifactId>
    				<configuration>
    					<archive>
    						<manifest>
    							<addClasspath>true</addClasspath>
    							<mainClass>com.taobao.top.appstore.App</mainClass>
    						</manifest>
    					</archive>
    				</configuration>
    			</plugin>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-assembly-plugin</artifactId>
    				<configuration>
    					<archive>
    						<manifest>
    							<mainClass>com.taobao.top.appstore.App</mainClass>
    						</manifest>
    					</archive>
    					<descriptorRefs>
    						<descriptorRef>jar-with-dependencies</descriptorRef>
    					</descriptorRefs>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    	......
    </project>
     

    注意上面的jar-with-dependencies,这样就会把jar包和它的所有runtime依赖添加到一个jar包中了,

  12. 装配
    tonglin@tonglin-desktop:~/maven-test$ mvn assembly:assembly
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'assembly'.
    [INFO] ------------------------------------------------------------------------
    [INFO] Building maven-test
    [INFO]    task-segment: [assembly:assembly] (aggregator-style)
    [INFO] ------------------------------------------------------------------------
    [INFO] Preparing assembly:assembly
    [INFO] ------------------------------------------------------------------------
    [INFO] Building maven-test
    [INFO] ------------------------------------------------------------------------
    [INFO] [resources:resources]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /home/tonglin/maven-test/src/main/resources
    [INFO] [compiler:compile]
    [INFO] Nothing to compile - all classes are up to date
    [INFO] [resources:testResources]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /home/tonglin/maven-test/src/test/resources
    [INFO] [compiler:testCompile]
    [INFO] Nothing to compile - all classes are up to date
    [INFO] [surefire:test]
    [INFO] Surefire report directory: /home/tonglin/maven-test/target/surefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.taobao.top.appstore.AppTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.089 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0添加到类路径
    
    [INFO] [jar:jar]
    [INFO] Building jar: /home/tonglin/maven-test/target/maven-test-1.0-SNAPSHOT.jar
    [INFO] [assembly:assembly]
    [INFO] Processing DependencySet (output=)
    [INFO] Building jar: /home/tonglin/maven-test/target/maven-test-1.0-SNAPSHOT-jar-with-dependencies.jar
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 9 seconds
    [INFO] Finished at: Tue Dec 22 13:56:56 CST 2009
    [INFO] Final Memory: 13M/24M
    [INFO] ------------------------------------------------------------------------
     

    运行上面的命令,就会在target目录下生成maven-test-1.0-SNAPSHOT-jar-with-dependencies.jar

  13. 运行
    tonglin@tonglin-desktop:~/maven-test$ java -jar target/maven-test-1.0-SNAPSHOT-jar-with-dependencies.jar
        Hello World!
     

    运行成功,一切OK,如果我们想在打包阶段,自动运行assembly插件的assembly目标,那么只需少许的改动

  14. 打包阶段自动运行assembly
    <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">
    	......
    	<build>
    		<plugins>
    			......
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-assembly-plugin</artifactId>
    				<configuration>
    					<archive>
    						<manifest>
    							<mainClass>com.taobao.top.appstore.App</mainClass>
    						</manifest>
    					</archive>
    					<descriptorRefs>
    						<descriptorRef>jar-with-dependencies</descriptorRef>
    					</descriptorRefs>
    				</configuration>
    				<executions>
    					<execution>
    						<id>make-assembly</id>
    						<phase>package</phase>
    						<goals>
    							<goal>single</goal>
    						</goals>
    					</execution>
    				</executions>
    			</plugin>
                            ......
    		</plugins>
    	</build>
    	......
    </project> 

    这样,我们再次运行:

    tonglin@tonglin-desktop:~/maven-test$ mvn clean package
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------------------------------------
    [INFO] Building maven-test
    [INFO]    task-segment: [clean, package]
    [INFO] ------------------------------------------------------------------------
    [INFO] [clean:clean]
    [INFO] Deleting directory /home/tonglin/maven-test/target
    [INFO] [resources:resources]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /home/tonglin/maven-test/src/main/resources
    [INFO] [compiler:compile]
    [INFO] Compiling 1 source file to /home/tonglin/maven-test/target/classes
    [INFO] [resources:testResources]
    [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory /home/tonglin/maven-test/src/test/resources
    [INFO] [compiler:testCompile]
    [INFO] Compiling 1 source file to /home/tonglin/maven-test/target/test-classes
    [INFO] [surefire:test]
    [INFO] Surefire report directory: /home/tonglin/maven-test/target/surefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.taobao.top.appstore.AppTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.077 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] [jar:jar]
    [INFO] Building jar: /home/tonglin/maven-test/target/maven-test-1.0-SNAPSHOT.jar
    [INFO] [assembly:single {execution: make-assembly}]
    [INFO] Processing DependencySet (output=)
    [INFO] Building jar: /home/tonglin/maven-test/target/maven-test-1.0-SNAPSHOT-jar-with-dependencies.jar
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 13 seconds
    [INFO] Finished at: Tue Dec 22 14:40:54 CST 2009
    [INFO] Final Memory: 17M/34M
    [INFO] ------------------------------------------------------------------------
     

    注意:上面配置package,运行的是assembly:single,而不是assembly:assembly,这两者有什么区别呢:

    • assembly:assembly 这个目标会自动执行package生命周期
    • assembly:single 这个目标仅会装配成jar-with-dependencies,我们不想让package阶段运行两次package,所以配置成这个
  15. 参考资料:
  16. 项目源代码:
    • Windowd平台:maven-test.zip
    • Linux平台:maven-test.tar.gz

希望这篇文章能够让有同样经历的同学,减少困惑,有任何问题请联系我!

5
1
分享到:
评论
7 楼 bo_hai 2016-05-30  
assembly:single 不包含源代码,只包含依赖的class信息。assembly:assembly 都包含。不知道为啥。
很好的解决hadoop依赖第三方jar的问题。
6 楼 lsy 2012-10-19  
相当详细的好文!
5 楼 seedpip 2011-09-08  
看到了放翁的名字
楼主的step by step教程很好!
在eclipse里面直接打包,还可以用fatjar插件。
4 楼 aaronjiu_00 2010-08-15  
rmn190 写道
真是多谢!


不过有一个问题: 装配完的jar名字除正常的外,还带了一个“...jar-with-dependencies.jar”, 请问下这个去掉?



不好意思,时到今日,才看到你的回复,可能你自己已经解决了这个问题,但是我还是把答案告诉你吧,也可以帮助其他有同样问题的同学。
其实这个问题很简单,只需要在assembly的configure节点加上appendAssemblyId,值为false,即:
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-assembly-plugin</artifactId>
	<configuration>
		<appendAssemblyId>false</appendAssemblyId>
		<archive>
			<manifest>
				<mainClass>com.taobao.top.appstore.App</mainClass>
			</manifest>
		</archive>
		<descriptorRefs>
			<descriptorRef>jar-with-dependencies</descriptorRef>
		</descriptorRefs>
	</configuration>
	<executions>
		<execution>
			<id>make-assembly</id>
			<phase>package</phase>
			<goals>
				<goal>single</goal>
			</goals>
		</execution>
	</executions>
</plugin>
3 楼 rmn190 2010-07-13  
真是多谢!


不过有一个问题: 装配完的jar名字除正常的外,还带了一个“...jar-with-dependencies.jar”, 请问下这个去掉?

2 楼 wannago 2010-02-02  
Thanks a lot!
1 楼 iamxiaole 2010-01-05  
非常好,解决了我的问题!

相关推荐

Global site tag (gtag.js) - Google Analytics