在做产品时,我们经常会遇到这样的需求:
- 打Jar包时,需要压入产品的版本信息,甚至还有版权信息。
- 在运行时,程序需要读取版本信息来做显示或者做分支处理。
一、最简单的实现方式 - manifest
public class VersionInfo {
public static String getVersion() {
Package pkg = VersionInfo.class.getPackage();
return (pkg != null ? pkg.getImplementationVersion() : null);
}
}
这也是Spring的实现方法,但关键是版本信息的元数据来自哪里?这些信息存于Jar包内的MANIFEST.MF文件。该文件用于描述jar的情况,具体请见:http://baike.baidu.com/view/1857179.htm
这些属性中,和版本信息相关的属性是:
Implementation-Version: xxxx
二、ANT + manifest
build.xml
使用Eclipse自动生成build.xml后,在build.xml内增加这么几行:
<property name="binary.version" value="1.0-SNAPSHOT" /> <target name="package" description="package a jar" depends="cleanall, build-project"> <jar jarfile="target/binary_version.jar" basedir="eclipse-build"> <manifest> <attribute name="Implementation-Version" value="${binary.version}" /> <attribute name="Main-Class" value="com.joshua.version.YourService" /> </manifest> </jar> </target>
第一行是存放版本号的字段。名为package的target则负责把版本号压入manifest并制作jar包。
*注意:我存放class文件的目录是eclipse-build,大家需要把这个路径改成自己的目录(一般都是bin)
使用ant package命令打包,Jar包会生成在工程根目录下的target文件夹下。使用命令:java -jar binary_version.jar执行。就可以看到控制台上打印出来的版本信息了。
*注意:上述方式有个问题,就是不打包的情况下(比如在IDE里执行),是获取不到版本号的。
带SVN版本号的版本信息
当然现实的情况不可能这么简单,版本信息一般会带上Revision。比如,SVN的版本号。针对SVN,我们可以在build.xml里加个target:
<target name="svnCheck" description="Use SVN to get the current revision" unless="disable-svnCheck"> <exec executable="svn" logerror="true" outputproperty="svn.exec.result" failonerror="true" failifexecutionfails="true"> <arg line="info"/> </exec> <loadresource property="svn.revision"> <string value="${svn.exec.result}"/> <filterchain> <linecontains> <contains value="Last Changed Rev: "/> </linecontains> <tokenfilter> <!-- Remove all but the revision number --> <replaceregex pattern=".*: " replace=""/> </tokenfilter> <striplinebreaks/> </filterchain> </loadresource> <echo level="info" message="svn.revision=${svn.revision}"/> </target>
三、使用Annotation来实现
这种方式,我在Hadoop的源码中看到过,虽然繁琐,不过也挺有意思。优点是在非打包情况下也能工作。思路是定义1个Package级的annotation,annotation里定义了版本等属性。然后使用脚本自动获取版本信息并生成package-info.java,通过package-info传递Annotation的所有参数(包括版本信息),并且指定包名。在代码中使用反射获取被指定包的这个annotation,来获取版本信息。关于package-info的介绍,我这里就不做介绍了,google一下你就知道。
Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface HadoopVersionAnnotation {
/**
* Get the Hadoop version
* @return the version string "0.6.3-dev"
*/
String version();
...
}
生成package-info的脚本我就不给了,因为不同项目实现也不同。下面给出被生成的package-info.java:
@HadoopVersionAnnotation(version="1.0.3"...【省略其他属性】)
package org.apache.hadoop;
接着,在代码里可以使用如下方式获取版本信息:
myPackage = HadoopVersionAnnotation.class.getPackage();
version = myPackage.getAnnotation(HadoopVersionAnnotation.class);
按上述方式,如果使用shell来生成package-info,那么我仍需要获取到软件的版本信息。版本可能源于SVN,或者GIT等等。下面提供些shell脚本供大家参考。
获取git的revision:
revision=`git log -1 --pretty=format:"%H"`
获取git的branch名
branch=`git branch | sed -n -e 's/^* //p'`
获取SVN的revision
revision=`svn info | sed -n -e 's/Last Changed Rev: \(.*\)/\1/p'`