`

Netbeans Platform: 注册与发现的机制

    博客分类:
  • java
阅读更多

Netbeans Platform: 注册与发现的机制

Netbeans Platform是模块化的设计。我们看一下最基本的开发思路:

例如,我们想要写一个XML验证器模块。我们会做一下几个事情:

1. 设计Validator接口, 定义一些验证所需的方法。方便以后提供Manifest验证器,html验证器等。

2. 设计实现Validation类,这个类维护一个Validator的Map, 允许添加和删除Validatior,如果需要验证的话,这个类会遍历Validator找出响应的Validator实现。

3. 实现XMLValidator类,实现Validator接口

4. 实现XMLModuleInstall类,继承ModuleInstall类。这个类维护一个静态的Validation类,完成XMLValidator的注册和去注册任务

这里有个问题,就是上述办法包含太多的样板代码。例如Validation中要维护注册许多验证器。每个模块需要提供Validator的实现类的同时,还要编写另一个类继承ModuleInstall类来完成注册和去注册的任务, 例如XMLValidator还要XMLModuelInstall, XMLValidator负责验证任务,XMLModuelInstall负责注册和去注册XMLValidator. 通过ModuleInstall程序在启动时都要加载验证器,不管你到底用不用它。

所以,Netbeans Platform需要一个好的注册模式。

我们先看看其他已经存在的注册模式:

java.awt.Toolkit使用一种基于属性的解决方案,property-based.

public Toolkit getDefaultToolkit() {
java.awt.Toolkit t = null;
String classname =
System.getProperty("java.awt.Toolkit"); // 从系统中获得java.awt.Toolkit属性:类名称
if (classname != null) {
try {
Class c = Class.forName(classname); // 根据类名称获得响应的类
t = (java.awt.Toolkit) c.newInstance(); // 使用类创建类实例
} catch (Exception ex) {
System.out.println
("Cannot initialize toolkit: " + classname);
ex.printStackTrace();
}
}
// Fallback
if (t == null) {
t = new GenericAWTToolkit(); // 如果都不成功,返回一个通用的默认的实例
}
}

这种解决方案比以前有进步,没有烦人的setter方法和注册方法,不过它需要你在Java虚拟机运行时正确的设置属性。你不得不在程序启动时初始化。

我们看看Netbeans Platform如何做这件事情。首先,设计理念是,基于现有的标准,需要的时候作些增强,必须很好的和Netbeans运行时容器提供的动态模块环境相匹配。这种解决方案必须对任何接口和类都适合才行。并且它要支持监听器,允许任何人监听已经注册了的对象的任何变化。例如,监听一个模块的激活和失活。

Netbeans Platform如何做到这一点呢?让我们看看:Lookup!

MetaInf Service 元信息服务

JDK1.3的时候,Java提出了一个概念:服务提供者,Service Provider.这个概念介绍了一种完全是声明式的注册机制。实际上这种注册机制完全基于Java虚拟机的当前类路径,并没有什么其他的东西。这种注册机制使用Java类路径定义注册了的对象,非常容易使用。改变注册提供者,仅仅需要将提供者的jar包放在应用程序的类路径上就可以了。这样提供者能够迅速被查找到并且可以被其他代码访问。

背后的基本思想是每个希望提供某些接口实现的jar文件(Netbeans的术语就是模块),例如javax.xml.parser.DocumentBuilderFactory的实现,能够创建自己的接口实现,比如org.saxon.MyFactory. 然后通过在自己jar包中创建一个META-INF/services/javax.parser.DocumentBuilderFactory文件的方式暴露给系统,这被称为系统中的服务。这个文件中每一行包含一个实现类的名字。在这个例子中,这个文件中存在:org.saxon.MyFactory一行,文件名字就是接口,里面的内容的一行就是一个实现。

我们看一下如何运行的呢?当你使用DocumentBuilderFactory.newInstance()来创建一个实现实例的时候,系统会扫描所有的META-INF/services/javax.parser.DocumentBuilderFactory文件。如何扫描呢?通过ClassLoader.getResources("META-INF/services/javax.parser.DocumentBuilderFactory"). 系统将会读取文件的内容,通过默认构造器创建实例。究竟那一个实现会被创建呢?答案是第一个。

这种方式很好,也很流行了,在JDK1.6中,更是增加了一个辅助类java.util.ServiceLoader. 使用这个类,能更加容易的查找到所有注册的服务,不用手工编写“查找,读取,实例化”的代码。因此在JDK1.6中上述的任务简化为:

return ServiceLoader.load(DocumentBuilderFactory.class, someClassLoader).iterator().next();

OK, 让我们回到Netbeans上,Netbeans的解决方案基于上述技术。它被称为Lookup!

全局Lookup

org.openide.util.Lookup, 它和java.util.ServiceLoader一样是service provider模式。你可能要问,为什么你要单独搞出这么个东西?原因如下:

1. 如果你使用JDK1.6以前的版本(虽然不太可能),你可以使用Lookup作为替代

2. Lookup能够立刻在Netbeans运行时容器中使用。它知道如何发现系统中的模块,并且读取他们定义的服务。

3. Lookup支持监听器。客户代码可以设置监听器,监听Lookup内容的变化。这在动态环境中非常重要,模块可以在运行时激活或者失活,从而影响一系列注册服务的提供者。

4. Lookup可以扩展和替代。JDK1.6的java.util.ServiceLoader是最终类,并且是硬编码的,而Lookup是可扩展的类,允许各种实现,这在单元测试中尤其重要。甚至你可以编写一个增强版的Lookup, 让它不仅仅从META-INF/services中读取信息。

5. Lookup是通用的抽象层。每个classloader可以有一个JDK的ServiceLoader实例,而在Netbeans中可以有成千上万个相互独立的Lookup,每个可以代表一个单一的位置去发现和查询服务和接口。事实上,这正是Netbeans使用Lookup的方式:他代表每个对话,窗口元素,树中节点等的上下文。

我们重新看一下Validation的例子,在先前的例子中,Validation依靠维护一个Validator的Map进行注册和去注册。那么使用Lookup后,Validation根本不需要这个Map,代码如下:

package org.netbeans.examples.validate.api;
import org.openide.util.Lookup;
public final class Validations {
private Validations() {}

// 将Validator.class定制为一个Lookup模版 Lookup.Template,

// 通过Lookup获得Validator.class的模版查找到Lookup.Result结果

// 这个结果包含所有找到的Validator实例,遍历这些实例,找到相应的Validator实例来验证


private static Lookup.Result<Validator> validators =
Lookup.getDefault().lookup(
new Lookup.Template<Validator>(Validator.class)
);
// Or in 6.0 version just:
// Lookup.Result<Validator> validators =
// Lookup.getDefault().lookupResult(Validator.class);


public static void validate(String mimeType, InputStream is)
throws IOException {
for (Validator v : validators.allInstances()) {
if (v.supportsMimeType(mimeType)) {
v.validate(is);
return;
}
}
throw new IOException("No validator found for " + mimeType);
}
}

使用Lookup不仅省却了Validation的Map,而且不需要registerValidator等方法。全部依赖于Lookup.getDefault的实现和其注册方式。这样Validation类只需关注validate方法就可以了。

看看吧,现在如果我们想实现另一个验证器Manifest Validator. 我们不再需要知道ModuleInstall或者在模块初始化和结束化调用任何方法。我们仅仅需要声明ManifestValidator实现了Validator接口就可以了:

package org.netbeans.examples.manifestvalidator;
public final class ManifestValidator implements Validator {
public boolean supportsMimeType(String mimeType) {
return "text/x-manifest".equals(mimeType);
}
public void validate(InputStream is) throws IOException {
// Just try to read the file as manifest:
Manifest mf = new Manifest(is);
}
}

接下来怎么将ManifestValidator注册呢?很简单,在META-INF目录下创建META-INF/services/org.netbeans.examples.validate文件,告诉人们存在实现这个接口的实现,然后在这个文件中增加一行:org.netbeans.examples.manifestvalidator.ManifestValidator。告诉人们ManifestValidator实现了这个接口。万事OK了!记住啊,我们有个org.netbeans.examples.manifestvalidator包,这个包包括一个META-INF目录,这个目录下有一个以接口名字命名的文件,这个文件中有一行实现类的类名,注册完成了!

分享到:
评论
1 楼 BigDataSmallWorld 2014-08-20  
前辈,您好:
    看了你的文章很受启发,最近在为了看代码需要和netbeans打交道,但是之前没接触过,今天看到这篇文章特地注册了个账号有问题想问。
    netbeans的开发模式我还不清楚,但是我新建netbeans模块->netbeans平台应用程序后发现点击运行按钮就能启动,可是程序里面并没有我很熟悉的main函数,可以说说netbeans的这种启动机制么,因为我要看的源码里面也是这种情况,但是也是可以启动,让我不知道从和开始看起。

相关推荐

    The.Definitive.Guide.to.NetBeans.Platform.7.pdf.rar

    2. **组件和服务**:掌握如何在NetBeans Platform中定义和使用服务,理解组件之间的依赖关系,以及如何通过服务注册和查找机制实现组件间的协作。 3. **可视化设计器**:熟悉NetBeans IDE中的可视化组件编辑器,...

    The Definitive Guide to NetBeans Platform 7

    - **操作与命令**:讨论了NetBeans中的动作体系,包括动作的注册、触发和执行机制。 - **数据和文件管理**:涵盖了文件系统集成、数据对象和节点的概念。 #### 用户界面开发(第2部分) - **菜单栏与工具栏**:...

    The Definitive Guide to NetBeans Platform 7 源代码

    4. **服务层**:平台提供了公共服务注册和查找机制,使得模块可以通过服务接口获取功能,而不是直接依赖具体的实现类,增强了代码的可扩展性和可维护性。 5. **可视化构建工具**:源代码中可能包含了用于创建用户...

    The Definitive Guide to NetBeans Platform 2009

    本书覆盖的是NetBeans Platform 6.5版本。 #### 二、NetBeans平台结构 在第二章中,作者深入介绍了NetBeans平台的基本结构,包括核心组件、模块系统以及这些组件如何协同工作来构建复杂的应用程序。理解平台的架构...

    actiongui-netbeans-modules

    【标题】"actiongui-netbeans-modules" 是一个与NetBeans集成开发环境相关的项目,它主要关注的是在NetBeans中创建和管理用户界面(GUI)的动作(Actions)。在Java编程中,Action是Swing库中一个关键的概念,它允许...

    JavaEE6Tutorial I

    - **商标**:文中列出了多个 Sun Microsystems 及其子公司的注册商标和商标,如 Java、EJB、JSP 等。 - **许可证**:对于政府用户,适用 Sun 的标准许可协议以及 FAR 和其补充条款。 #### 六、结论 Java EE 6 是一...

    J2EE.Web.Services.2003

    5. **UDDI注册**:介绍Universal Description, Discovery, and Integration(UDDI)服务注册和发现机制,以及如何在J2EE环境中集成UDDI。 6. **安全与事务管理**:讨论Web服务的安全性问题,包括认证、授权、加密和...

    百宝箱业务应用程序开发规范-JAVA分册

    - **注册与认证**:SP需要在中国移动的平台上完成注册,并通过认证。 - **内容审核**:所有Java业务都需经过严格的审核流程,确保内容合法合规。 - **技术支持与售后服务**:SP需要提供技术支持和售后服务,解决用户...

    java学习资料 入门到半精通

    后来,考虑到Oak已被注册,改名为Java。 - **发展:** 随着全球信息网(World Wide Web)的兴起,Java Applet成为了网页互动技术的重要组成部分。1995年5月23日,Sun公司正式发布了Java Development Kit (JDK) 1.0a2...

    用户登录 小程序

    1. **J2EE(Java 2 Platform, Enterprise Edition)**:J2EE是Java平台的企业版,它提供了一个用于构建企业级分布式应用程序的框架和API。该平台包括服务器端组件模型、服务(如EJB、Servlet、JSP)、以及用于处理...

    J2EE入门教程

    - **定义与背景**:J2EE(Java 2 Platform, Enterprise Edition)是Sun Microsystems为简化企业级应用开发而提出的一种标准规范和技术平台。它基于Java SE平台,并在此基础上增加了许多面向企业级应用的新特性。 - *...

    Java Web Services Tutorial

    Java Web Services 技术随着Java Platform, Enterprise Edition (Java EE) 的发展而不断进步。在2006年发布的Java Web Services Developer’s Pack v2.0中,Sun Microsystems(现已被Oracle收购)提供了全面的教程和...

    JavaServerFace入门

    此外,JSF与CDI(Contexts and Dependency Injection for the Java EE Platform)无缝集成,提供了更强大的DI功能。 7. 开发工具: 开发JSF应用时,常见的IDE如Eclipse、NetBeans和IntelliJ IDEA都有很好的JSF支持...

    IIIT ejb网上购物

    EJB是Java EE(Java Platform, Enterprise Edition)框架的一部分,它为开发者提供了创建可部署在企业级应用服务器上的分布式、事务处理和安全的业务组件的标准。EJB主要包括三种类型的组件:Session Beans(会话...

    Java界面开发学习笔记.doc

    安装SWT Designer时,需要从官方网站下载对应版本,然后通过Eclipse的links机制进行安装和注册。 除了Swing和SWT的基本使用,笔记还涵盖了其他高级特性,如实现拖拽效果、QQ窗口自动隐藏、自定义控件库、欢迎界面...

    electronicwallet:Java EE中内置的Ebanking Plateforme

    项目描述中提到,这个"electronicwallet"是内置在Java EE中的Ebanking Platform的克隆版本,这意味着它可能包含了完整的银行业务流程,从用户注册、登录,到资金转账、余额查询等。开发者可以通过下载此项目,将其...

    JAVA上百实例源码以及开源项目源代码

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等... //在服务器上注册 InputStream is=ftpClient.list(); //得到服务器目录与文件列表输入流 StringBuffer info=new StringBuffer...

Global site tag (gtag.js) - Google Analytics