MetaData Programme
作者:Anders小明
1.1. 什么是元数据编程
什么是元数据,元数据就是描述数据的数据(data about data)。最明显的例子是XML Schema,xml schema就是描述xml的数据,所以它是元数据。另一个例子是数据库,比如我们可以查询数据库中有几个表,每个表都有什么字段,这些数据就是元数据。
在开发的世界里,元数据就是能够绑定到一个类的附加信息,在静态或者运行时间。JCR175给我们提供annotation就是一种元数据。
不过在这之前一个我们已经广泛使用的元数据是XML,如就是EJB的XML发布描述符中,你需要定义基于每一个方法的事务属性。应用服务器指导什么时候,什么地方开始,挂起或者提交一个事务,因为你在BEAN的XML的配置文件中的元数据内已经定义如方法:Required,RequiresNew,Support等等,它们绑定在你的EJB类和事务管理之间。XDoclet是另一个元数据的例子。
1.2. Annotation的意义和简单例子
JDK1.5提供的annotation与我们所常见的classes、fieldss和methods间是什么关系。如下:如果说类和数据成员是名词,方法是动词,那么annotation就是形容词或者副词,分别描述它们的所具有属性。
好,现在就来实现一个annotation
import java.lang.annotation.Retention;
package sample.annotation;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface Broker {
String name();
String address();
}
}
使用这个annotation
Import sample.annotation.broker;
@Broker(name="anders", address="
public class Agent {
public String getTelPhone (){
return "010-0592-2519280";
}
}
运行期得到这个annotation
public class
public static void main(String[] args){
Agent agent = new Agent();
try{
Annotation[] a = agent.getClass().getMethod("getBrokerName").getAnnotations();
for (int i=0; i<a.length ; i++) {
if( a[i] instanceof Broker){
Broker broker = (Broker)a[i];
System.out.println(broker.name());
}
}
}
catch(Exception e){
e.printStackTrace(System.out);
}
}
}
1.3. Annotation的class文件格式
利用sun公司的提供的javap,我们可以看到annotation的在class文件中的表示。以下为对比结果:
源码:
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface Broker {
String name();
String address();
}
Javap结果:
Compiled from "Broker.java"
interface Broker extends java.lang.annotation.Annotation
SourceFile: "Broker.java"
minor version: 0
major version: 0
Constant pool:
const #1 = class #9; // Broker
const #2 = class #10; // Object
const #3 = class #11; //Annotation
const #4 = Asciz name;
const #5 = Asciz ()Ljava/lang/String;;
const #6 = Asciz address;
const #7 = Asciz SourceFile;
const #8 = Asciz Broker.java;
const #9 = Asciz Broker;
const #10 = Asciz java/lang/Object;
const #11 = Asciz java/lang/annotation/Annotation;
{
public abstract java.lang.String name();
public abstract java.lang.String address();
}
源码:
public interface Broker {
String name();
String address();
}
Javap结果:
Compiled from "Broker.java"
interface Broker
SourceFile: "Broker.java"
minor version: 0
major version: 0
Constant pool:
const #1 = class #8; // Broker
const #2 = class #9; // Object
const #3 = Asciz name;
const #4 = Asciz ()Ljava/lang/String;;
const #5 = Asciz address;
const #6 = Asciz SourceFile;
const #7 = Asciz Broker.java;
const #8 = Asciz Broker;
const #9 = Asciz java/lang/Object;
{
public abstract java.lang.String name();
public abstract java.lang.String address();
}
源码:
@Broker(name="anders", address="
public class Agent {
public String getTelPhone(){
return "0592-2519580";
}
}
Javap结果:
Compiled from "Agent.java"
public class Agent extends java.lang.Object
SourceFile: "Agent.java"
RuntimeVisibleAnnotations: length = 0x10
00 01 00 11 00 02 00 12 73 00 13 00 14 73 00 15
minor version: 0
major version: 0
Constant pool:
const #1 = Method #4.#22; // java/lang/Object."<init>":()V
const #2 = String #23; // 0592-2519580
const #3 = class #24; // Agent
const #4 = class #25; // Object
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Asciz LineNumberTable;
const #9 = Asciz LocalVariableTable;
const #10 = Asciz this;
const #11 = Asciz LAgent;;
const #12 = Asciz getTelPhone;
const #13 = Asciz ()Ljava/lang/String;;
const #14 = Asciz SourceFile;
const #15 = Asciz Agent.java;
const #16 = Asciz RuntimeVisibleAnnotations;
const #17 = Asciz LBroker;;
const #18 = Asciz name;
const #19 = Asciz anders;
const #20 = Asciz address;
const #21 = Asciz
const #22 = NameAndType #5:#6;// "<init>":()V
const #23 = Asciz 0592-2519580;
const #24 = Asciz Agent;
const #25 = Asciz java/lang/Object;
// 以下为方法域,略
源码:
public class Agent {
public String getTelPhone(){
return "0592-2519580";
}
}
Javap结果:
Compiled from "Agent.java"
public class Agent extends java.lang.Object
SourceFile: "Agent.java"
minor version: 0
major version: 0
Constant pool:
const #1 = Method #4.#16; // java/lang/Object."<init>":()V
const #2 = String #17; // 0592-2519580
const #3 = class #18; // Agent
const #4 = class #19; // Object
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Asciz LineNumberTable;
const #9 = Asciz LocalVariableTable;
const #10 = Asciz this;
const #11 = Asciz LAgent;;
const #12 = Asciz getTelPhone;
const #13 = Asciz ()Ljava/lang/String;;
const #14 = Asciz SourceFile;
const #15 = Asciz Agent.java;
const #16 = NameAndType #5:#6;// "<init>":()V
const #17 = Asciz 0592-2519580;
const #18 = Asciz Agent;
const #19 = Asciz java/lang/Object;
// 以下为方法域,略
补充说明:我们都知道在java 1.0发布时,java class file的格式就已经定下来,要说明的是为了应未来的需要java class file设计了属性说的机制。一直到j2se1.4都没有怎么改变。但这次为了更好的支持metadata技术,一共增加了8个属性。分別是:
「EnclosingMethod」Attribute :Anonymous Class 或 Local Inner Class 使用此 Attribute 描述该Class 的Scope。
「Signature」 Attribute:Generics 的 Class、Method、或 Filed使用此 Attribute 来记录所要的类型,因为java的范型采用了擦拭法。
「LocalVariableTypeTable」 Attribute:主要是給 debugger 使用,目的和「LocalVariableTable