这个类是个比较普通的类,但是管理了hadoop的版本信息,包括用户、编译时间、版本信息等内容。在这个类中,封装了HadoopVersionAnnotation这个注释类。由于个人觉得这个设置挺巧妙,值得学习,所以特别拿出来说明进行分享。
下面就VersionInfo的几个调用场景进行说明
(1)打印系统版本信息。运行hadoop VERSION时,对应的执行类即为VersionInfo在main中直接打印消息。
public static void main(String[] args) {
System.out.println("Hadoop " + getVersion());
System.out.println("Subversion " + getUrl() + " -r " + getRevision());
System.out.println("Compiled by " + getUser() + " on " + getDate());
System.out.println("From source with checksum " + getSrcChecksum());
}
(2)在namenode等后台进程启动时,会调用StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);打印当前的进程和系统消息。
其中startupShutdownMessage打印进程启动或停止的消息日志。
当进程启动时:
LOG.info(
toStartupShutdownString("STARTUP_MSG: ", new String[] {
"Starting " + classname, //打印类名
" host = " + hostname, //机器名和IP地址
" args = " + Arrays.asList(args), //参数列表
" version = " + VersionInfo.getVersion(), //后面的都是从VersionInfo获取的系统信息。
" build = " + VersionInfo.getUrl() + " -r "
+ VersionInfo.getRevision()
+ "; compiled by '" + VersionInfo.getUser()
+ "' on " + VersionInfo.getDate()}
)
);
当进程停止时,执行run中的内容。可以搜索addShutdownHook,即可理解这部分代码。这个部分和VersionInfo无关,只是顺便说明。
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
LOG.info(toStartupShutdownString("SHUTDOWN_MSG: ", new String[]{
"Shutting down " + classname + " at " + hostname}));
}
});
好了,到此为止,对VersionInfo的功能进行了介绍,下面介绍其工作的原理。
(3)VersionInfo的工作原理。
定义了静态变量:myPackeage和version。其中version是HadoopVersionAnnotation的实例。HadoopVersionAnnotation是Annotation接口类,在这里,hadoop项目组通过这种方式来获取系统版本信息。并不是直接写在代码中。后面会说到,这实际是从build过程就开始的工作。
private static Package myPackage;
private static HadoopVersionAnnotation version;
static {
myPackage = HadoopVersionAnnotation.class.getPackage();
version = myPackage.getAnnotation(HadoopVersionAnnotation.class);
}
/**
* Get the meta-data for the Hadoop package.
* @return
*/
static Package getPackage() {
return myPackage;
}
/**
* Get the Hadoop version.
* @return the Hadoop version string, eg. "0.6.3-dev"
*/
//代码较多,这里就取getVersion()方法来说明,实际是获取了HadoopVersionAnnotation实例的version()方法的返回值。
public static String getVersion() {
return version != null ? version.version() : "Unknown";
}
}
(4)话不多说,介绍HadoopVersionAnnotation类
package org.apache.hadoop;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE) //是对包的注释,很多地方都是用ElementType.METHOD类型来对方法进行定义,但是这里用PACKAGE类型。
public @interface HadoopVersionAnnotation {
/**
* Get the Hadoop version
* @return the version string "0.6.3-dev"
*/
String version(); //这个version()方法就是上面VersionInfo中getVersion()方法中调用的方法。
}
但是纵观全类,这只是个接口类,并没有实现。查看整个项目的源码,也没有找到初始化的地方。
因为之前不了解Annotation是什么,自己也是查的百度,才大概理解,就不在这里介绍了,不了解的朋友可自行百度或谷歌。
总之,如果类型设置为PACKAGE,则需要在这个Annotation所在的包中,有一个package-info.java类,并且定义如下:
@HadoopVersionAnnotation(version="1.0.4-SNAPSHOT")
package org.apache.hadoop;
这样,在调用HadoopVersionAnnotation的version()方法时,就可以得到在package-info.java中对该方法的返回值的定义了。
(5)下面,就要介绍这个package-info.java是怎么来的了。
比如build date,或者user这样的参数,不可能事先人为的写在package-info.java文件中的,而且查看源码,其实这个文件本来是没有的~
下面贴出package-info.java文件的源码,可以发现,原来这个文件是由src目录下的saveVersion.sh文件生成的!
/*
* Generated by src/saveVersion.sh
*/
@HadoopVersionAnnotation(version="1.0.4-SNAPSHOT", revision="",
user=aperson", date="Tue Aug 21 01:28:38 PDT 2012", url="",
srcChecksum="ec890fc9af4c24bcba23ee1b2dca7857")
package org.apache.hadoop;
到这里为止,就对整个过程了解了。
下面就需要知道在什么地方调用了saveVersion.sh脚本,可以查看build.xml文件,发现有下面一句话:
<exec executable="sh">
<arg line="src/saveVersion.sh ${version} ${build.dir}"/>
</exec>
到此为止,就了解了VersionInfo的整个工作过程。