• 信步漫谈之Ant—打包可运行的Jar包(加入第三方jar包)


    介绍使用 Ant 打包可运行的 Jar 包。

    打包 jar 包最大的问题在于如何加入第三方 jar 包使得 jar 文件可以直接运行,以下用实例进行说明。

    程序结构:

    image

    关键代码:

    package com.alfred.main;
    
    import com.alfred.bean.User;
    import com.alfred.util.ProjConfig;
    import com.thoughtworks.xstream.XStream;
    
    public class Main {
    	public static void main(String[] args) {
    		User user = new User();
    		user.setUsername("alfred");
    		user.setAge(15);
    		XStream xstream = new XStream();
    		String xml = xstream.toXML(user);
    		System.out.println("in Main");
    		System.out.println("prop:"+ProjConfig.MY_PROPERTY);
    		System.out.println("xml:"+xml);
    	}
    }
    Main.java
    <?xml version="1.0" encoding="UTF-8"?>
    <project basedir="." default="usage" name="antproj">
    	<!-- 引入配置文件 -->
    	<property file="build.properties" />
    	<!-- 配置引用属性 -->
    	<property name="src.dir" value="src" />
    	<property name="config.dir" value="config" />
    	<property name="build.dir" value="build" />
    	<property name="lib.dir" value="lib" />
    	<property name="name" value="antproj" />
    
    	<path id="master-classpath">
    		<fileset dir="${lib.dir}">
    			<include name="*.jar" />
    		</fileset>
    		<pathelement path="${build.dir}" />
    	</path>
    
    	<target name="usage">
    		<!-- 输出信息到控制台中 -->
    		<echo message="" />
    		<echo message="${name} build file" />
    		<echo message="-----------------------------------" />
    		<echo message="" />
    		<echo message="Available targets are:" />
    		<echo message="" />
    		<echo message="build     --> Build the application" />
    		<echo message="" />
    	</target>
    
    	<!-- 编译生成class文件 -->
    	<target name="build"
    		description="Compile main source tree java files">
    
    		<!-- 删除编译存放的classes文件 -->
    		<delete dir="${build.dir}/classes"></delete>
    		<!-- 新建编译存放的classes文件 -->
    		<mkdir dir="${build.dir}/classes" />
    		<copy todir="${build.dir}/classes">
    			<!-- 将项目中除会编译生成class文件的java文件之外其他类型的文件拷贝到对应的目录下,指定文件名后缀 -->
    			<fileset dir="${src.dir}">
    				<include name="**/*.properties" />
    				<include name="**/*.xml" />
    			</fileset>
    			<fileset dir="${config.dir}">
    				<include name="**/*.properties" />
    			</fileset>
    		</copy>
    		<!-- java编译 -->
    		<javac destdir="${build.dir}/classes" source="1.5" target="1.5"
    			debug="true" deprecation="false" optimize="false" failonerror="true"
    			encoding="utf-8">
    			<src path="${src.dir}" />
    			<!-- 编译所需要的jar包路径 -->
    			<classpath refid="master-classpath" />
    		</javac>
    	</target>
    
    	<target name="jar" depends="build"
    		description="Compress the java class files to jar">
    
    		<mkdir dir="${build.dir}/jar" />
    		<delete file="${build.dir}/jar/${name}.jar" />
    		<buildnumber file="${build.dir}/buildnum.txt" />
    		<!-- 指定时间戳 可以调用TODAY -->
    		<tstamp>
    			<format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" />
    		</tstamp>
    
    		<!-- 生成清单文件 -->
    		<manifest file="${build.dir}/MANIFEST.MF">
    			<attribute name="Built-By" value="${user.name}" />
    			<attribute name="Implementation-Version"
    				value="${version.num}.${build.number}" />
    			<attribute name="Built-Date" value="${TODAY}" />
    			<attribute name="Main-Class" value="com.alfred.main.Main" />
    		</manifest>
    
    		<!-- 打包jar -->
    		<!-- includes 包含哪些后缀文件 空格分隔 -->
    		<jar destfile="${build.dir}/jar/${name}.jar"
    			basedir="${build.dir}/classes"
    			includes="**/*.class **/*.properties **/*.xml"
    			manifest="${build.dir}/MANIFEST.MF">
    			<zipfileset src="${lib.dir}/xstream-1.4.9.jar"></zipfileset>
    			<zipfileset src="${lib.dir}/xpp3-1.1.3.3.jar"></zipfileset>
    		</jar>
    	</target>
    
    	<target name="cleanup">
    		<!-- 删除编译文件夹下的所有文件(不包括编译文件夹下的文件夹)
    		<delete>
    			<fileset dir="${build.dir}/classes" includes="**/*.*" />
    		</delete>
    		 -->
    		<!-- 删除编译文件夹 -->
    		<delete dir="${build.dir}/classes" />
    	</target>
    </project>
    build.xml

    将第三方 jar 包加入的关键代码是:

    <zipfileset src="${lib.dir}/xstream-1.4.9.jar"></zipfileset>
    <zipfileset src="${lib.dir}/xpp3-1.1.3.3.jar"></zipfileset>

    这种情况下生成的 jar 包内部结构如下:

    imageimage

    可以看到第三方 jar 包实际上都被拆开打包进我们的 jar 包了。如果使用的第三方 jar 包太多的话,会变得非常混乱。这时可以通过单独将程序打包为 jar 包,通过引用的方法调用外部第三方 jar 包的方式运行。

    如果使用如下的写法:

    <zipfileset dir="${lib.dir}">
        <include name="*.jar"/>
    </zipfileset>

    那么打包生成的 jar 包将无法正常调用第三方 jar 包,jar 包结构如下:

    imageimage

    可以看到第三方 jar 包都是完整的。

    由以上示例可知,无论是将第三方 jar 包拆分打包(结构混乱)还是保持第三方 jar 包完整打包(无法正常运行),都存在一定的问题,以下介绍一种通过引用的方式调用第三方 jar 包的方式。

    在 build.xml 中新建一个任务

    <target name="jar2" depends="build" description="Compress the java class files to jar">
        <mkdir dir="${build.dir}/jar" />
        <delete file="${build.dir}/jar/${name}.jar" />
        <buildnumber file="${build.dir}/buildnum.txt" />
        <!-- 指定时间戳 可以调用TODAY -->
        <tstamp>
            <format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" />
        </tstamp>
    
        <pathconvert property="quote.classpath" pathsep=" ">
            <mapper>
                <chainedmapper>
                    <!-- jar包文件只留文件名,去掉目录信息 -->
                    <flattenmapper />
                    <!-- add lib/ prefix -->
                    <globmapper from="*" to="lib/*" />
                </chainedmapper>
            </mapper>
            <path refid="master-classpath" />
        </pathconvert>
    
        <!-- 生成清单文件 -->
        <manifest file="${build.dir}/MANIFEST.MF">
            <attribute name="Built-By" value="${user.name}" />
            <attribute name="Implementation-Version" value="${version.num}.${build.number}" />
            <attribute name="Built-Date" value="${TODAY}" />
            <attribute name="Main-Class" value="com.alfred.main.Main" />
            <attribute name="Class-Path" value="${quote.classpath}" />
        </manifest>
    
        <!-- 打包jar -->
        <!-- includes 包含哪些后缀文件 空格分隔 -->
        <jar destfile="${build.dir}/jar/${name}.jar"
            basedir="${build.dir}/classes"
            includes="**/*.class **/*.properties **/*.xml"
            manifest="${build.dir}/MANIFEST.MF">
        </jar>
    </target>

    将关联的第三方 jar 包通过路径转换加上路径前缀(也就是之后你 jar 包引用第三方 jar 包的路径),生成新的路径信息 quote.classpath,将路径信息配置进 Class-Path 属性,通过这种方式生成的 jar 包中 MANIFEST.MF 文件内容中 Class-Path 如下:

    Class-Path: lib/xpp3-1.1.3.3.jar lib/xstream-1.4.9.jar

    之后我们将第三方 jar 包放置于 lib 目录中,将打包后的 antproj.jar 放置于和 lib 同级目录,运行 jar 正常。

    另外,要打包可运行的 jar 包,加入第三方 jar 包的话,也可以通过一些 IDE 的插件,例如:fatjar。

  • 相关阅读:
    线程简介
    JDBC连接数据库遇到的“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。
    项目开发中需要考虑的问题2
    JPA使用中遇到Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: XXX is not mapped
    ORA-01747: user.table.column, table.column 或列说明无效
    IDEA使用一套代码启动多个应用
    tomcat8.5部署管理控制台
    ubuntu16虚拟机迁移/移动/复制后无法上网
    centos7没有IP地址
    repmgr自动故障转移的参数配置
  • 原文地址:https://www.cnblogs.com/alfredinchange/p/5372657.html
Copyright © 2020-2023  润新知