分享
 
 
 

MetaData Programme

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

MetaData Programme

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="xiamen")

public class Agent {

public String getTelPhone (){

return "010-0592-2519280";

}

}

运行期得到这个annotation

public class Main {

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="xiamen")

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 xiamen;

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」 Attribute类似,只是「LocalVariableTable」 Attribute 记录所要的参数表,而「LocalVariableTypeTable」 Attribute 记录参数的类型。

「RuntimeVisibleAnnotations」 Attribute:确定该annotation可以被reflection的API返回,适用对象:Class、Method、Field

「RuntimeInvisibleAnnotations」 Attribute:确定该annotation无法被reflection的API返回,适用对象: Class、Method、Field。

「RuntimeVisibleParameterAnnotations」 Attribute:同「RuntimeVisibleAnnotations」 Attribute,适用对象:Method,(该Method 的参数

「RuntimeInvisibleParameterAnnotations」 Attribute:同「RuntimeInvisibleAnnotations」 Attribute,适用对象:Method,(该Method 的参数。

「AnnotationDefault」 Attribute:适用对象:Method,记录默认值。

1.4. 为什么需要Annotation

在annotation之前我们已经广泛使用另外一种元数据xml,为什么需要annotation。Annotation与xml的作为元数据的区别是什么——位置。Annotation写在源代码中,而xml写在外部。

为什么要这样?如果你开发过EJB,你一定为你的EJB写过xml描述文件。当大量的EJB需要描述时,就出现了所谓的"descriptor hell"。这个也导致了著名的XDoclet的出现。而annotation出现可以避免这种descriptor hell。另外你更改了某个方法为其增加或者减少一个参数,你就对应的修改xml文件,而使用annotation则不必。使用annotation将开发和部署更方便,提供开发效率。

另外:使用xml的另一个问题是:很多Xml配置太过verbose。相比较EJB和Hibernate 或者Webwork可以明显的发现不同。

1.5. 再议Annotation

在EJB3中,Annotation把开发和部署的工作合在一起。但是在一些企业环境中,开发人员并不控制诸如数据源名等(这些是部署部门和管理部门的工作),这样把数据源名写在xml中将比较好。

Annotation是本身静态的,一旦添加或者修改annotation都需要重新编译,在运行时读取,这样就丧失了运行时配置的能力。因此Annotations 不会取代xml,它只是提供了另一种途径。并且我相信sun公司将在未来提供一个方式可以在运行期更改metadata。

关于这点TSS上有着很激烈的讨论,很多开发人员提出:利用xml来更改annotation,并希望类似的方式能被采纳为标准规范。比如使用如下格式:

<class name="org.hibernate.Item">

@Entity

@Table(name="AUCTION_ITEM")

<method sig="getBar()">@Transient</method>

<method sig="doSomething(int, String)">

@Tx(REQUIRES_NEW)

</method>

</class>

当然也有不同意见:But then, I think of "overriding" as a different problem to "xml deployment descriptors", and so I think we need two solutions. I think Cedric and Bill are trying to kill two birds with one stone, so maybe their proposals are better....

关于为annotation提供动态配置能力的问题,其中一个网友认为:Sun make it real pain to do the deployment XML so that they can introduce annotation to fix it. The annotation can make code/deployment coupling so strong that Sun can come out with a new way (annotation interceptor in jdk 1.6? :)) for fixing it. and the cycles goes on...这让我想起了类似的现象:JSP和TagLib。希望Annotation不会和TagLib有同样的命运。

Annotation本身引入另一种类型的接口。在EJB3中确实使程序更加POJO,也消除了一些接口。并且编译后的代码也可以直接移植到另一个并不处理这些annotations的环境中(感谢VM在加载类时并不检查那些annotations的classes,甚至这些类不在classpath中)。然而代码也确实增加了另一些接口。这个表现在编译期,如果没有这些annotation classes,是编译不过的。

另一个问题(还好不算很重要),关于annotation的namespace。在多层应用的系统中,可能会出现同样的全局annotation的namespace冲突。比如一些公共的annotation,如@Transaction,将会被应用在很多个层次中。尽量让namespace长些,可以避免这个问题。

1.6. 元数据编程的应用:

Annotation已经被集成到很多的java规范和标准中,很重要的是它已经被J2EE标准,如EJB3所采用,当然也被许多开源的组件体系如:AspectJ。

Annotation最重要的应用将是AOP:由于annotation可以天然的表示系统中的另一个横切面,同时Annotation的识别是通过反射得到的,所以Annotation很自然的应用到基于动态代理的AOP实现。AOP-Alliance也支持metadata handling。AspectJ也发布了基于annotation的新版本。

在实现AOP上,使用annotation也比使用XML有一个优势:如前所述,annotation更像是形容词和副词,这样比较不容易verbose。当然这个是相对的,在实际的实现中更依赖开发人员的努力。

这里,笔者将展示一个不完整也不成熟的基于annotation的AOP例子代码——关于银行卡的例子。

功能需求:银行卡业务分为转帐,查询余额,查询明细,POS消费等。这其中转帐和POS消费是要收费的(转帐收取的是用户的手续费,而POS消费收取的是商家的手续费),另外POS消费还可能有积分的(比如笔者的牡丹贷记卡)。消费转帐都要记录明细。但查询余额就不需要记录在明细中。

代码如下(在这个例子没有用动态代理也没有用已有的AOP框架,使代码看起来简单些)

// 银行卡对象

public class Card {

private String account;

//some field method

}

Annotation:

// 手续费

// type= "user", 表示收取用户手续费; type= "Biz", 表示收取商家手续费

public @interface Fee{

String type();

}

// 积分

public @interface Index {

}

// 记录明细

public @interface BizLog {

}

// 事务处理

public @interface Transaction {

}

// 业务接口

public interface BizAction {

void execute(Card card, RunData rundata);

}

// 转帐业务

@Fee(type="user")

@Transaction

@BizLog

public class TransferAction implements BizAction {

public void execute(Card card, RunData rundata) {

//To change body of implemented methods use File | Settings | File Templates.

}

}

// POS消费

@Fee(type="Biz")

@Transaction

@BizLog

@Index

public class POSAction implements BizAction {

public void execute(Card card, RunData rundata) {

//To change body of implemented methods use File | Settings | File Templates.

}

}

// 查询明细

public class QueryDetail implements BizAction {

public void execute(Card card, RunData rundata) {

//To change body of implemented methods use File | Settings | File Templates.

}

}

// 业务操作监视器接口

public interface BizActionMonitor {

void execute(BizAction action, RunData rundata);

}

// 业务操作监视器实现

public class BizActionMonitorImpl implements BizActionMonitor{

public void execute(BizAction action, RunData rundata) {

Annotation[] annotations = action.getClass().getAnnotations();

for(Annotation annotation : annotations){

if (annotation instanceof Fee){ // 计算手续费 }

if (annotation instanceof Index){ //计算积分 }

if (annotation instanceof Transaction){ // 准备事务 }

if (annotation instanceof BizLog){ // 记录明细 }

}

}

}

// 控制器对象

public class controller{

private BizActionMonitor monitor;

public void execute(BizActionUI, rundata){

BizAction action = getAction(BizActionUI);

monitor.execute(action, rundata);

}

}

// 运行时数据

public interface RunData {

// some method

}

// 用户设备(POS机, ATM或者柜台终端)接口

public class BizActionUI {

private RunData rundata;

private Controller controller;

public BizActionUI(RunData rundata, Controller controller){

this.rundata = rundata;

this.controller = controller;

}

public void execute(){ // 某个子类实现 }

public void commit(){

controller.execute(this, rundata);

}

}

public class Main{

private Rundata rundata;

private Controller controller;

public populateUI(command){

BizActionUI ui = getUI(command);

ui.execute();

}

public BizActionUI getUI(command){

//...

BizActionUI ui

if( //....){

ui = new SomeBizActionUI(rundata, controller);

}

return ui;

}

public static main(String[] args){

//...

Main main = new Main();

main.populateUI(command)

//...

}

}

1.7. 结束语:

本文讨论了annotation技术,展示了annotation的class文件格式,并讨论了annotation技术本身的优势和不足,并于现有的xml技术加以比较,展望了annotation技术的应用前景AOP。

限于笔者自身的水平(包括技术水平和写作水平),技术上对annotation的学习比较有限,写作上也感觉好多话无法用文字来表达,因而本文的代码会比较多(大概有一半以上)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有