`

java meta-date 元数据(1)

阅读更多

转自:http://book.csdn.net/bookfiles/427/10042715309.shtml

7.2  关于元数据

系统开发中存在各种各样的数据,比如Tom是一个年龄为30岁的男性员工、Liliy是一个21岁的女性员工、这张报表是今年第三季度的利润表、那张报表是今年上半年的销售波动图、对话框上有三个按钮控件、窗口上有一个多行文本控件和一个保存按钮、这个WebService提供了股票实时情况查询的服务、那个WebService提供了查询天气预报的服务。

以上数据存在很多共性的特征,这些特性都可以通过某种形式进行抽象。

对于“Tom是一个年龄为30岁的男性员工”、“Liliy是一个21岁的女性员工”,在数据库级别就会抽象成含有FId Varchar(50)、FName Varchar(50)、FAge(int)、FSex(int)四个字段的数据库表T_Employee,在Hibernate中就被抽象成含有id、name、age、sex四个字段的JavaBean以及对应的hbm配置文件。

这些数据是平台无关的,在描述“Tom是一个年龄为30岁的男性员工”这条数据的时候,它即可以是保存在数据库中的,也可以是保存在XML配置文件中的,甚至有可能只是写在一张便条上的。与此相反的是,对这些数据的抽象方式大都是与特定平台相关的,是无法移植的。比如要把数据的存储方式由数据库改为XML文档,那么就必须针对XML文件的存取特点重新进行抽象。由于抽象方式是平台相关的,这些抽象出来的模型就不具有通用性,无法通过统一的方式来读取它们。比如要读懂T_Employee这张表中的字段的含义就要去查阅数据字典,要读懂便条上的“Tom 30 m”就要去询问写便条的人。

元数据(MetaData)是MDA中非常重要的概念。它通过统一的、平台无关的、规范的方式对数据的模式特征进行描述,通过一个模型结构来表达通用的信息,它集设计模型、开发模型与运行模型为一体。元数据具有如下几个作用。

(1) 元数据是独立于平台的,无论使用什么技术平台,元数据本身是不受影响的,这保证了先期工作成果的效用最大化。

(2) 元数据是生成平台相关模型的基础,可以使用代码生成器等工具将元数据转换成平台相关代码。

(3) 元数据为运行时系统提供了统一的可读的系统模型,系统运行时可以使得实体对象通过运行时元数据模型来得知自身的结构、自身的特征、在系统模型中的位置以及与其他对象之间的关系等。这样就可以从一个新的角度来观察、设计、开发系统。

(4) 元数据模型是系统运行不可或缺的部分,如果直接修改平台相关代码而不修改元数据,就会造成系统运行异常,这就强迫保证元数据模型与代码同步,保证了设计模型和实现代码的一致性。

(5) 元数据本身就是一个设计模型。系统设计人员可以使用元数据进行系统建模,在某种程度上元数据可以取代UML图等传统的设计模型。设计人员将设计完成的元数据模型交给开发人员,开发人员使用代码生成器将元数据转换成平台相关代码,然后就可以基于这些平台相关代码进行开发了。元数据起到了设计人员和开发人员沟通桥梁的作用,设计人员的工作立即就可以转换为可以运行的平台相关代码。

7.2.1  元数据示例

枚举类型在不同的系统中有不同的表示方式,而且有不同的模型描述方式(即枚举有哪些项、项的值是多少等信息),有的平台还没有提供足够的模型描述方式。客户类型包括:普通客户、会员客户、VIP客户。

在JDK 1.5中可以表示为enum CustomerTypeEnum{Normal, Member, VIP},取得CustomerTypeEnum枚举类型中定义的所有枚举项的方法为CustomerTypeEnum.values(),取得“Normal”这个字符串对应的枚举项的方法为Enum.valueOf(CustomerTypeEnum.class, "Normal")。

在JDK 1.4中使用Apache Commons包提供的Enum类可以表示为:

public class CustomerTypeEnum extends org.apache.commons.lang.enums.Enum

{

    public static DataTypeEnum Normal= new DataTypeEnum("Normal");

    public static DataTypeEnum Member= new DataTypeEnum("Member");

    public static DataTypeEnum VIP= new DataTypeEnum("VIP");

    private DataTypeEnum(String name)

    {

        super(name);       

    }

}

取得CustomerTypeEnum枚举类型中定义的所有枚举项的方法为EnumUtils.get- EnumList(CustomerTypeEnum.class),取得“Normal”这个字符串对应的枚举项的方法为EnumUtils.getEnum(CustomerTypeEnum.class, "Normal")。

在C#中,可以表示为enum CustomerTypeEnum{Normal, Member, VIP},取得Customer- TypeEnum枚举类型中定义的所有枚举项的方法为Enum.GetNames(typeof(CustomerTypeEnum)),取得“Normal”这个字符串对应的枚举项的方法为Enum.Parse(typeof(CustomerTypeEnum), "Normal")。

在Delphi中,可以表示为type CustomerTypeEnum=(Normal, Member, VIP);没有提供取得CustomerTypeEnum枚举类型中定义的所有枚举项的方法,取得“Normal”这个字符串对应的枚举项的方法也没有直接提供,必须借助RTTI。 

要将一个平台上的CustomerTypeEnum移植到另一个平台,必须用目标平台的枚举语法重新改写,而且使用的取得枚举类描述信息的方式也要发生变化,这都给系统的移植带来了很大的工作量。

【例7.1】元数据示例。

为了解决这个问题,我们设计一个元数据模型:

<Enum>

    <Name>CustomerTypeEnum</Name>

    <Items>

        <Item name="Normal" displayName="普通客户"></Item>

        <Item name="Member" displayName="会员客户"></Item>

        <Item name="VIP" displayName="VIP客户"></Item>

    </Items>

</Enum>

提供一个描述这个元数据模型的描述类:

//枚举描述类

public class EnumInfo

{

    …

    //得到所有的枚举项

    public EnumItemInfo[] getEnumItems();

    //得到名字为name的枚举项的信息

    public EnumItemInfo getEnumItem(String name);  

}

//枚举项描述类

public class EnumItemInfo()

{

    …

    //枚举项的名字

    public String getName();

    //枚举项的显示信息

    public String getDisplayName();    

}

提供一个读取元数据模型的API:

public class EnumMetaDataLoader

{

    …

    //加载元数据类型enumTypeName对应的元数据模型

    public EnumInfo loadEnum(String enumTypeName)

    {

        …

    }

}

枚举元数据模型的描述类和读取元数据模型的API的实现代码仍然是平台相关的,因为这些类都是要被特定平台使用的。因为XML解析在各个平台是大同小异的,所以这些描述类和API的实现方式的移植是非常简单的。

使用这样的元数据模型我们还可以定义其他的枚举类型,比如:

<Enum>

    <Name>SexEnum</Name>

    <Items>

    <Item name="Male" displayName="男"></Item>

    <Item name="Female" displayName="女"></Item>

    </Items>

</Enum>

在JDK 1.4平台下,使用代码生成器将SexEnum的元数据模型转换成JDK 1.4下的枚举代码:

public class SexEnum extends org.apache.commons.lang.enums.Enum

{

    public static SexEnum Male= new DataTypeEnum("Male");

    public static SexEnum Female= new DataTypeEnum("Female");

    private SexEnum String name)

    {

        super(name);       

    }

}

当要得到所有SexEnum 定义的枚举项的时候,按如下方式调用:

EnumInfo enumInfo = EnumMetaDataLoader.getInstance().loadEnum("SexEnum");

EnumItemInfo[] itemInfos = enumInfo.getgetEnumItems();

for(int i=0,n=itemInfos.length;i<n;i++)

{

    EnumItemInfo itemInfo = itemInfos[i];

    System.out.println("项名称:"+itemInfo.getName()

            +";显示名称:"+getDisplayName());

}

这样我们不用再去调用特定平台的API实现了,元数据信息提供了比平台API更多的功能,并且写出的代码不会受平台API的限制。  

若某天客户提出要增加一种“不详”的性别类别,如果开发人员直接修改生成的SexEnum 类,在其中加入“不详”的性别类别的枚举定义的话,系统就会工作不正常,因为没有修改SexEnum 元数据。这样就限制了开发人员直接修改SexEnum 类,这样开发人员只能去修改SexEnum 元数据,然后用代码生成器来重新生成SexEnum 类代码。这规范了开发人员的行为,保证了设计模型与实现代码的一致性。   

若某一天,公司决定将开发平台从Java迁移到C#,那么对于枚举这部分需要做的改造工作就是用C#重写元数据模型描述类和元数据读取API,并开发一个针对C#枚举的元数据转换器,系统所有的枚举就都可以自动转换成C#下的了。这保证了前期对于枚举元数据模型的设计开发成本利用的最大化。

由于枚举在各个平台之间差异并不算大,而且一个平台整体从Java迁移到C#的可能性也非常小,所以元数据在这里起到的作用并不大。但是在Java平台上ORM工具的迁移倒是很有可能的,要想体会元数据的更重要的作用就要看案例系统的实体元数据了。

7.2.2  元元数据

元数据是对数据共性的抽象,而不同的元数据本身也是具有共性的,以上一节的两个枚举元数据来说,客户类型枚举元数据与性别枚举元数据为共同的模式:

<Enum>

    <Name>枚举名称</Name>

    <Items>

    <Item name="名称" displayName="显示名称"></Item>

        …

    </Items>

</Enum>

可以定义一种模型来描述所有枚举元数据的共性特征,也就是枚举元数据的元数据(Metadata of metadata)。这种对元数据进行抽象描述的形式被称为元元数据(MetaMetaData)。

7.2.3  设计时与运行时

元数据的直接表示形式被称为设计时元数据,而在运行的时候能被系统读取的形式(比如上边的EnumInfo)被称为运行时元数据。通常,运行时元数据描述的特性是设计时元数据的特性的子集。

系统承担着设计模型与运行时模型的多重责任,而且元数据还作为代码生成器的“源”,承载着描述目标代码的作用。这些责任之间有相交的部分,也有自己独特的部分。举例来说,一个描述实体对象的元数据,它描述这个实体对象有哪些字段、字段的类型是什么、和其他实体对象之间有什么关系等信息,而作为代码生成器的“源”,它还要描述一些目标平台特有的东西,比如当目标平台为Hibernate的时候,就需要指定主键字段的生成策略、关联字段的LazyLoad策略、Casade策略等。从严格意义上来讲,为了维持元数据的平台无关性,这些平台相关的特性是不能放在元数据中的,而应该放在一个描述平台相关属性的地方,不过这样就使得元数据模型过于复杂。一个较好的策略是在元数据中增加一个专门存放这些平台相关属性的区域。      

运行时的元数据是要被平台相关代码访问的,如果运行时元数据中包含平台相关特性的话,就会导致以后平台移植难度加大,而且也混淆了设计时语义与运行时语义之间的界限。所以运行时的元数据中一定不能包含平台相关特性。

7.2.4  元数据设计的基本原则

除了上边提到的运行时的元数据中一定不能包含平台相关特性之外,在元数据的设计中,“适可而止”也是需要铭记在心的核心原则。对元数据描述的范围要适可而止,不要试图包罗万象。运行时元数据是能够给运行时的系统提供元数据的信息的,这在一定程度上简化了系统的开发,但是切不可把应该写在代码中或者写到配置文件中的信息写到元数据中。比如在实体对象元数据中,给字段增加了“allowNull”特性来表示此字段是否允许为空。系统保存实体对象的时候,可以读取此实体对象对应的元数据,进而取得所有字段的是否为空的特性,从而对数据进行校验。这是对运行时元数据非常合理的运用。但是如果试图把字段为空时提示什么样的信息、字段最大长度是多少、字段是否进行加密操作等特性加入元数据的话就会使得元数据模型过于庞大,这也违反了“适可而止”这一基本原则。如果元数据直接驱动系统的运行过程,并且有取代程序代码的趋势的话,就说明设计人员对元数据概念理解错误了,用元数据驱动系统运行虽然减少了代码的编写,但是这些本不应该放在元数据中的特性是不完备的,一旦需要扩展就会遇到难以逾越的鸿沟。

由于客户需求的复杂性,模型结构不能表达出所有业务的处理过程,仍然存在需要利用编程语言才能完成的业务功能。元数据模型解决大多数通用的问题,而对于具有差异性的问题还是要通过编码来完成的,不应该让运行时元数据承担过多的运行时语义。

7.2.5  此“元数据”非彼“元数据”

元数据这个词汇并不是MDA发明的,在其他领域“元数据”早已经被使用了,在软件开发领域,“元数据”也不是MDA中才有的。

JDK 5.0的annotation机制也被称为元数据,它为属性的物理驻留位置提供了新的选择。annotation使得代码具有自解释的能力,代码变成能同时提供行为及自我描述能力的实体,也就是说代码从一维变成二维的了。使用JDK提供的API就可以从代码中读取到这些描述信息。

/**

*@ filedName = "FName" type = "Varchar(44)"

*/

public String getName(){…}

这段代码中类似JavaDoc的东西就是annotation,它描述了name这个属性对应着数据库中的类型为“Varchar(44)”名称为“FName”的字段。Hibernate3、EJB3都推荐并且支持这种方式。

在Hibernate本身也有元数据机制,在Hibernate的包org.hibernate.metadata中的类就是提供元数据支持的API,通过它们能读取到一个实体对象有哪些字段、字段的类型是什么、是否允许为空、是否关联其他的实体对象等。

JDK的annotation、Hibernate中的元数据都符合元数据的定义,它们也是真正的元数据。它们与MDA中的元数据的最主要区别就是是否具有平台无关性。很显然JDK的annotation、Hibernate中的元数据都不能脱离它们所依赖的平台,元数据中有很多描述平台专有属性的东西,无法作为一个跨平台的元数据引擎使用。不过这些元数据能反应平台的更多的细节,如果合理利用将极大地提高开发效率。在后边关于HibernateDTOGenerator的分析中读者将会看到我们是如何使用Hibernate的元数据来实现DTO产生器的。

<!-- page -->
分享到:
评论

相关推荐

    Java开发技术大全(500个源代码).

    narrowingConversion_1.java 缩减转换引发错误示例1 narrowingConversion_2.java 缩减转换引发错误示例2 notMultipleOfThree.java 把100-200之间不能被3整除的数输出 outputByDoWhile.java 用while循环随机输出...

    Java_JDK1.8

    除了元注解(meta-annotations)和自定义注解,Java 8还引入了多重注解,允许在一个元素上使用多个相同的注解实例,增强了注解的灵活性和可扩展性。 总的来说,Java JDK 1.8通过引入Lambda表达式、默认接口方法、...

    Java-HTTP协议讲解,使用初级人员入门学习

    - **头部信息**:包含关于响应的元数据,如日期、服务器类型等。 - **实体体**:如果有的话,这部分包含了实际的响应数据,例如请求的文件或错误消息。 例如,一个简单的响应可能如下所示: ```plaintext ...

    json-lib-2.0-jdk15-sources.zip

    5. **元信息(META-INF)**:在压缩包中的META-INF目录可能包含项目配置、版本信息和其他元数据。例如,MANIFEST.MF文件通常记录了项目的主类、依赖库和其他属性。 6. **net目录**:这部分源代码可能包含了与网络...

    又拍云 java对接

    1. **又拍云Java SDK安装与配置** 首先,你需要从官方仓库或GitHub获取`java-sdk-master`压缩包,解压后将SDK导入到你的Java项目中。如果是Maven项目,可以在`pom.xml`中添加依赖。如果没有使用构建工具,可以将jar...

    modern-java-practice

    9. **反射和注解的增强**:Java提供了更强大的反射机制,以及元注解(meta-annotations)和自定义注解的使用,使得代码可以更好地自我描述,提高代码的可维护性和扩展性。 10. **字符串和集合的优化**:Java对字符...

    JDK 1.8 doc

    7. **Meta-Object Protocol (MOP)**:元对象协议允许动态语言在Java平台上更好地运行,JDK 1.8提供了对Java代理(Java proxies)的增强,使得它们可以更好地模拟动态语言的行为。 要使用这个文档,首先你需要下载并...

    Java Web应用开发 24 课堂案例-使用response刷新页面.docx

    在Java Web应用开发中,页面刷新是一个常见的需求,特别是在实时更新数据或持续显示最新状态的场景下。本案例主要讲解如何使用`response`对象的`setHeader`方法来实现页面的自动刷新。以下是对该知识点的详细说明: ...

    SpringMVC第一天学习代码

    `META-INF`通常包含项目的元数据,如`MANIFEST.MF`文件,而`WEB-INF`下则包含`web.xml`配置文件、`classes`和`lib`目录,分别用于存放编译后的类文件和项目依赖的JAR包。 通过这些知识点的学习,你应该能够初步掌握...

    hutool-all-5.4.2_如何用hutool-all_hutoll_hutool-all_

    1. **日期时间处理**:Hutool提供了丰富的Date和Calendar操作API,包括日期格式化、日期计算、时间间隔处理等。例如,你可以轻松地将日期转换为字符串,或者根据指定格式解析日期,极大地简化了日期相关的编码工作。...

    jas程序实现手表的自动刷新功能

    1. **元指令**: `%@ page language="java" ...` 这个指令告诉服务器此页面的主要语言是Java,并设置了页面的字符编码和内容类型。 2. **导入所需库**: `%@ page import="java.util.Date" %&gt;` 和 `%@ page import=...

    GriF.src.zip_Java编程_Java_

    5. "META-INF":这是Java应用程序的标准目录,包含了如MANIFEST.MF文件等元数据信息,这些信息对于构建、部署和运行Java应用程序是必要的。 6. "Images":这个目录可能包含了项目相关的图形资源,如图标、示例图片...

    自定义标签和自定义jstl函数的具体项目实现

    创建一个名为`fn.xml`的文件,放在`META-INF`目录下,定义函数库的元数据和函数。 ```xml &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;function-library&gt; &lt;name&gt;myfn &lt;namespace&gt;...

    javaWeb学习笔记

    - `&lt;head&gt;` 包含文档的元数据,如标题、CSS和JavaScript链接等。 - `&lt;title&gt;` 定义网页标题,在浏览器标签页显示。 - `&lt;meta&gt;` 用于指定字符集、视口设置等元信息。 - `http-equiv="content-type"` 设置内容类型...

    《大数据平台搭建与配置管理》期中试卷及答案.docx

    - **解析**: NameNode的主要职责包括管理文件系统的命名空间、维护文件系统的元数据等。它并不直接参与数据的读写操作。 6. **HDFS描述** - **知识点**: HDFS的关键特性及其应用场景。 - **解析**: HDFS适用于...

    android 第三方登录(友盟SDK)

    集成友盟SDK后,需要在AndroidManifest.xml文件中添加必要的权限和启动元数据。例如: ```xml &lt;uses-permission android:name="android.permission.INTERNET" /&gt; &lt;uses-permission android:name="android....

    jsp tag标签的使用

    1. 创建TLD(Tag Library Descriptor)文件:定义自定义标签的元数据,如标签名、属性、返回类型等。 ```xml &lt;tlib-version&gt;1.0&lt;/tlib-version&gt; &lt;jsp-version&gt;2.0&lt;/jsp-version&gt; &lt;short-name&gt;myTags&lt;/short-name...

    HTML,JSP页面缓存的解决方案

    ') == -1) { url += '?v=' + new Date().getTime(); } else { url += '&v=' + new Date().getTime(); } window.location = url; ``` 4. **服务器端处理**: - 在JSP页面中可以使用内置对象`response`来设置...

    Android widget(2-1)

    其中,`&lt;meta-data&gt;` 标签指向一个 XML 文件,该文件包含了小部件的元数据,比如它的图标、初始布局文件路径等。 **2. HelloWorld 实践** 创建一个简单的 HelloWorld 小部件涉及以下步骤: - 创建一个 `...

    web程序设计基础.pdf

    如`&lt;meta&gt;`标签用于设置页面元信息,`&lt;head&gt;`包含页面的元数据,`&lt;body&gt;`则是页面的主要内容区域。虽然这部分代码中没有显示,但通常还会用到`&lt;link&gt;`标签引入外部CSS样式表,以实现页面的美化。 2. **JSP语法**:...

Global site tag (gtag.js) - Google Analytics