在 java 中,可以在打包是往包里添加包的版本等基本信息,这有助于各版本包之间的协调,在分布式系统中也适用。
在 java 包中添加基本信息有两种方式,一是传统的往包的 MANIFEST.MF 文件中写信息,二是用注解。
1,往 MANIFEST.MF 写信息,包括:
如,java 的 util 包该文件内容如下:
该文件在打包时产生,信息由打包者输入。
以上信息将被 Java 虚拟机自动封装到 Package 对象中。假设包中包含 Test 类,那么用如下语句可以获取该包的信息:
2,用注解添加包的基本信息
在 java 中有几种级别的注解,包括变量级、方法级、类级和包级,我们可以添加包注解,并在注解中添加包基本信息。
对于包级注解,java 做了如下规定:
包注解只能用在文件名为 package-info.java 的源文件中,并且该源文件只有包声明的语句,在包声明语句之前添加注解类,如:
当 java 编译器碰到 package-info.java 文件的时候,它会为该文件产生一个名为 package-info.class 的文件,通过反编译可以看到该文件是一个抽象接口,如:
于是在运行过程中就可以通过该接口获取包级注解了。
可以通过 java.lang.Package 对象来获取包级注解,查看该类的源码,可以看到获取某个特定注解过程如下:
下面,写个简单例子,假设所有代码都在包 sample 下。
由上可以知道需要写的类有:
1.注解类:SampleAnnot.java(可以多个)
2.包级注解存放文件:package-info.java
3.我们再写个 Test.java
在 java 包中添加基本信息有两种方式,一是传统的往包的 MANIFEST.MF 文件中写信息,二是用注解。
1,往 MANIFEST.MF 写信息,包括:
Name The name of the specification.
Specification-Title The title of the specification.
Specification-Version The version of the specification.
Specification-Vendor The vendor of the specification.
Implementation-Title The title of the implementation.
Implementation-Version The build number of the implementation.
Implementation-Vendor The vendor of the implementation.
如,java 的 util 包该文件内容如下:
Name: java/util/
Specification-Title: Java Utility Classes
Specification-Version: 1.2
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: java.util
Implementation-Version: build57
Implementation-Vendor: Sun Microsystems, Inc.
该文件在打包时产生,信息由打包者输入。
以上信息将被 Java 虚拟机自动封装到 Package 对象中。假设包中包含 Test 类,那么用如下语句可以获取该包的信息:
Package myPackage = Test.class.getPackage();
myPackage.getImplementationVersion()
...
2,用注解添加包的基本信息
在 java 中有几种级别的注解,包括变量级、方法级、类级和包级,我们可以添加包注解,并在注解中添加包基本信息。
对于包级注解,java 做了如下规定:
包注解只能用在文件名为 package-info.java 的源文件中,并且该源文件只有包声明的语句,在包声明语句之前添加注解类,如:
@Annotation1(...)
package sample;
当 java 编译器碰到 package-info.java 文件的时候,它会为该文件产生一个名为 package-info.class 的文件,通过反编译可以看到该文件是一个抽象接口,如:
package sample;
@Annotation1(...)
abstract interface package-info{
}
于是在运行过程中就可以通过该接口获取包级注解了。
可以通过 java.lang.Package 对象来获取包级注解,查看该类的源码,可以看到获取某个特定注解过程如下:
应用程序调用 Package 的 getAnnotation 方法
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
return getPackageInfo().getAnnotation(annotationClass);
}
getAnnotation 方法再通过 getPackageInfo() 获得由编译器根据 package-info.java 文件产生的 package-info 接口,从而可以获得所有注解信息
private Class<?> getPackageInfo() {
if (packageInfo == null) {
try {
packageInfo = Class.forName(pkgName + ".package-info", false, loader);
} catch (ClassNotFoundException ex) {
// store a proxy for the package info that has no annotations
class PackageInfoProxy {}
packageInfo = PackageInfoProxy.class;
}
}
return packageInfo;
}
下面,写个简单例子,假设所有代码都在包 sample 下。
由上可以知道需要写的类有:
1.注解类:SampleAnnot.java(可以多个)
2.包级注解存放文件:package-info.java
3.我们再写个 Test.java
注解类:SampleAnnot.java,该类只有一个 field,就是 version
package sample;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface SampleAnnot {
String version();
}
-------------------------------------------------------------
package-info.java:该文件只有一行包的声明语句和一行注解
@SampleAnnot(version="1.0")
package sample;
-------------------------------------------------------------
Test.java:该文件获取包对象,并从包对象中获取包的注解信息,关于获取过程请参照上面源码分析
package sample;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// 获取 SampleAnnot 注解
SampleAnnot sampleAnnot = Test.class.getPackage().getAnnotation(SampleAnnot.class);
// 打印版本信息
System.out.println(sampleAnnot.version());
}
}