[转载]使用 Apache Geronimo 和 POJO 构建 SOA 框架

使用 Apache Geronimo 和 POJO 构建 SOA 框架


在不考虑库和框架强制执行的应用程序编程接口 (API) 约束的情况下进行软件开发,是一个非常诱人主张。它使许多人接受了普通旧式 Java™ 对象(Plain Old Java™ Object,POJO)编程的范例 —— 能够在 Java 平台上开发软件,而无需使用多余的接口或第三方 API。Apache Geronimo 框架为构建复杂应用程序和服务的 POJO 开发提供了一个可靠的基础设施。本文介绍 Geronimo 框架的一些组件和技巧,用于通过 POJO 策略来实现成功的、面向服务的开发。

面向服务的架构 (SOA)面向服务的编程 是两个术语,指软件工程的风格,它们将业务逻辑封装为模块化服务。这些服务以动态运行时环境为目标,在该环境中,服务提供者和服务消费者之间的关联是松散 耦合的。松散耦合的服务通常没有任何编译时关联,所以在运行时,您可以动态地将它们链接在一起,并允许开发人员根据需要灵活地做出开发决策。除松散耦合之 外,下列概念也是面向服务的环境中的公共概念:

  • 粗粒度:服务的粒度是指服务公开给出的功能范围。细粒度的服务 表示定义一定程度的功能性的公共接口。粗粒度的服务 表示较一般程度的功能性,通常适合于给定的业务领域。
  • 位置透明度 (Location transparency):位置透明度是指客户机在不考虑位置的情况下访问网络上的服务。
  • 协议独立性:协议独立性指客户机在不考虑通信/网络协议的情况下访问服务。

将服务与这些概念绑定在一起是一项艰难的任务。但 POJO 编程可以简化这一任务。

POJO 简介

POJO 是无需遵循特定外部接口或第三方 API 的 Java 类。此功能本身就是取消代码与外部关联的耦合。去耦的主要好处之一是让软件开发人员无需开发辅助任务(如持久性、事务支持和远程操作)。许多技术消除了组件/类的去耦,并促进了 POJO 编程,包括:

  • 注释是开发工具使用的、并用于生成代码的元数据,它可以 “装饰” 一个类或部分类,以支持给定类型的功能或特性,如远程操作、持久性和框架支持。
  • 依赖性注入是构建插入式 组件的技术,对象创建和关联是从组件移除的,并由容器或汇编组件实现。
  • 反射是运行时发现的关于给定类或接口的信息,如方法、字段和构造函数。

每种去耦技术都有其优点和缺点。本文将通过 POJO 编程构建一个简单的 SOA 框架,它使用反射和 Geronimo 的 GBean 依赖性注入来让组件去耦。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


JMX 和 Geronimo

Geronimo 构建在通用的内核基础上,它使用 Java Management Extensions (JMX) 和称为 GBean 的托管组件的依赖性注入框架。实际上,Geronimo 中的每件事物(适配器、应用程序和容器等)即是一个 GBean,也以 GBean 为基础。GBean 与 JMX 和 JMX Managed Beans (MBeans) 共享许多相似点和相同的底层基础设施。

c.gif
JMX

JMX 规范已经作为系统管理、应用程序管理和资源管理方面的 Java 标准出现。JMX 为使用用于管理目的的属性和操作动态增加 Java 类、接口和运行时对象定义了一个标准。此增加技术也称为 instrumentation

JMX 可以管理您使用 Java 编程语言抽象的任何资源(如应用程序、驱动程序或服务)。可以将每个托管资源叫做一个 MBean。JMX 定义了四个类型的 MBean:

  • 标准 MBean 使用 Java 接口定义它们的管理属性和操作。
  • 动态 MBean 使用运行时发现定义它们的管理属性和操作。
  • 模型 MBean 充当希望公开管理操作和属性的对象的代理。
  • 开放 MBean 使用预定义的元数据词汇公开类和对象的管理属性和操作。

与 MBean 交互的主要接口是 javax.management.MBeanServer。MBeanServer 充当 MBean 的中心库,并促进 MBean 与 MBean 客户机的通信。

ObjectName 对象可惟一地标识 MBean。ObjectName 实例包括:

  • 一个域,是给定域的任意名称;推荐使用逆向域名称系统 (DNS) 对域进行命名的约定,方式与 Java 包命名方式相同。
  • 一个键属性列表,是一个库,一组任意的、无序的键,并与值关联。

下列代码演示如何构造典型的 ObjectName 对象:

String domain = "com.jeffhanson.test";
String keyPropertyList =
"domain:Name=TestBean,Type=GenericService";
ObjectName objName =
new ObjectName(domain + ":" + keyPropertyList);

将 ObjectName 对象用作许多 MBeanServer 方法的参数,以便检索属性,并调用 MBean 上的操作。

Geronimo 的 GBean 框架

GBean 是 Geronimo 中的托管组件,这些组件共享许多相似点以及与 JMX MBean 的关系,如根据名为 GBeanInfo 的类公开属性和操作,该类与 JMX 替代物 MBeanInfo 类非常相似。Geronimo 将 MX4J 库(请参阅本文结尾的 参考资料)用作其 JMX 的实现。

GBean 维护状态和关联依赖性,并处理生命周期事件。GBean 可以注册为其他 GBean 状态中的相关方。启动相关 GBean 后,它将通过依赖性注入收到相关 GBean 的引用。GBean 在任何给定的时间可以处于下列七个生命周期状态之一:

  1. 已加载
  2. 未加载
  3. 将要开始
  4. 正在运行
  5. 将要停止
  6. 已停止
  7. 失败

清单 1 给出了一个包含一个属性(消息)的简单 GBean。



































清单 1. 典型的 GBean
public class TestGBean
implements GBeanLifecycle
{
private static GBeanInfo GBEAN_INFO = null;

static
{
GBeanInfoBuilder infoFactory =
GBeanInfoBuilder.createStatic(TestGBean.class);
infoFactory.addAttribute("message", String.class, true);
infoFactory.addOperation("getMessage");
GBEAN_INFO = infoFactory.getBeanInfo();
}

private String message;

public String getMessage()
{
return message;
}

...
}

您可以使用 清单 2 中给出的代码来启动(激活)和停止 GBean。


清单 2. 启动典型的 GBean
ObjectName testGBeanOName =
ObjectName.newInstance("jeffhanson.test:ID=test");
GBeanData gBeanData =
new GBeanData(testGBeanOName, TestBean.GBEAN_INFO);
gBeanData.setAttribute("message", "Hello world");
geronimoKernel.loadGBean(gBeanData,
Thread.currentThread().
getContextClassLoader());
geronimoKernel.startGBean(testGBeanOName);
...
geronimoKernel.stopGBean(testGBeanOName);
geronimoKernel.unloadGBean(testGBeanOName);

您可以在整个 Geronimo 内核中大量地使用 GBean。


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


Geronimo 内核

Geronimo 内核 是 GBean 的一个框架。使用此框架,您可以建模并构建任何复 杂的系统作为一组 GBean 容器和 GBean 组件,来管理状态、关系和事件处理。

使用 KernelFactory 类,以编程方式创建 Geronimo 内核是一个非常简单的过程。清单 3 说明如何通过启动内核、记录启动时间和加载并启动 servlet GBean 来创建名为 TestGeronimo 的新 Geronimo 内核。


清单 3. 创建一个简单的 Geronimo 内核
try
{
Kernel geronimoKernel =
BasicKernelFactory.newInstance().
createKernel("TestGeronimo");

geronimoKernel.boot();

log.debug("Geronimo BootTime: "
+ geronimoKernel.getBootTime());

// add the servlet GBean
ObjectName servletObjName =
new ObjectName("jeffhanson.test:ID=MyGBean");
GBeanData servletGBeanData = new GBeanData(servletObjName,
GBEAN_INFO);
ClassLoader classLoader = getClass().getClassLoader();
geronimoKernel.loadGBean(servletGBeanData, classLoader);
geronimoKernel.startGBean(servletObjName);
}
catch (Exception e)
{
log.error(e);
}

创建并运行内核后,调用 POJO 服务上的方法就变成了练习使用 Geronimo 内核服务器及其反射功能,如 清单 4 所示。


清单 4. 调用注册到内核的服务上的调用
private static
Object invokePOJOService(ObjectName serviceObjName,
String operationName,
String[] params)
throws Exception
{
String[] paramTypes = null;
if (params != null && params.length > 0)
{
paramTypes = new String[params.length];
for (int i = 0; i < params.length; i++)
{
paramTypes[i] = params[i].getClass().getName();
}
}

Kernel geronimoKernel =
KernelManager.getInstance().getGeronimoKernel();

Object retVal =
geronimoKernel.invoke(serviceObjName,
operationName,
(Object[])params,
paramTypes);

return retVal;
}


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


Geronimo 中面向服务的 POJO 的可适应框架

本 文中引用的用于 SOA 的 POJO 框架使用 Geronimo 内核实例将 POJO 注册为 GBean,相关客户机可以查询并调用它们,而无需其他接口或 API。框架驻留在多层企业级应用程序环境中的业务层中。服务定位符类负责与内核交互,以查找并注册(如果需要) 用作服务的 POJO。然后服务定位符类将 POJO 返回到调用它们的业务委派组件。图 1 说明了框架中组件的关系。


图 1. 用于 SOA 的 POJO 框架
用于 SOA 的 POJO 框架

该框架旨在从客户机接收 HTTP 请求,然后将请求传递到调度程序组件,该组件会发送消息,并将请求分派给业务委派组件。 然后,业务委派组件使用服务定位符找到特定请求的服务。业务委派组件调用该服务,并将任何返回值打包为模型对象。适当的视图组件将处理模型对象,并返回它作为对客户机的格式化响应。图 2 中的顺序图说明了这些步骤。


图 2. 典型 HTTP 请求和服务调用的往返顺序
典型 HTTP 请求和服务调用

图 3 中的类图说明了框架的类之间的关系。


图 3. 框架的类之间的关系
框架类之间的关系

blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


部署并运行框架

框架驻留在企业级应用程序系统的业务层中。该框架公开一个接收 HTTP 请求的 servlet,并将内容分派给框架进行处理。下一节将阐述简单的部署过程。

部署框架

您可以将框架的类和企业级应用程序打包在 .war 文件中,将其放置在 geronimo_home/deploy 目录下。如果此目录不存在,就创建它。

Geronimo 在启动时会自动部署 .war 文件。放置在 deploy 目录中的应用程序是热加载的,允许 Geronimo 在您做出更改时能够在运行时重新加载应用程序。这样使调试应用程序变得非常便利。

测试框架

您可以使用位于 geronimo_home/bin 目录中的启动脚本(startup.bat 或 startup.sh)启动 Geronimo 应用服务器。当调用 Geronimo 启动脚本时,可以看到 Geronimo 控制台窗口。部署框架和应用程序后,启动时的 Geronimo 控制台窗口包含类似于 清单 5 所示的行,确认 Web 应用程序已经成功启动。


清单 5. Web 应用程序已经成功启动的确认
0 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel  -
Starting boot
422 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for: :role=Kernel State changed from stopped to
starting
422 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for: :role=Kernel State changed from starting to
running
422 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel -
Booted
640 [main] DEBUG com.jeffhanson.apptier.FrontController - Geronimo
BootTime: Sat May 20 18:51:08 MDT 2006
656 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for: jeffhanson.test:ID=FrontController State
changed from stopped to starting
656 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for: jeffhanson.test:ID=FrontController State
changed from starting to running

现在,在 Web 浏览器窗口键入以下 URL,以激活 HelloWorld 服务上的 setMessage 操作:

http://:/?Action=
HelloWorld&Operation=setMessage&Params=Hello+everybody!

当框架处理请求时,控制台的输出结果应类似于 清单 6 所示。


清单 6. setMessage 操作处理的输出结果
719 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator  -
Adding service [HelloWorld] to kernel...
719 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator -
Loading GBean: jeffhanson.test:Name=HelloWorld,Type=GenericService
734 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for:
jeffhanson.test:Name=HelloWorld,Type=GenericService State changed
from stopped to starting
734 [main] DEBUG org.apache.geronimo.gbean.runtime.GBeanInstanceState
- GBeanInstanceState for:
jeffhanson.test:Name=HelloWorld,Type=GenericService State changed
from starting to running

在 Web 浏览器窗口中键入以下 URL,以激活 HelloWorld 服务上的 sayHello 操作:

http://:/?
Action=HelloWorld&Operation=sayHello

当框架处理请求时,控制台的输出结果应类似于 清单 7 所示。


清单 7. sayHello 操作处理的输出结果
750 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator  -
serviceObjName: jeffhanson.test:Name=HelloWorld,Type=GenericService
750 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator -
Service [HelloWorld] already in kernel
1156 [main] DEBUG com.jeffhanson.businesstier.ServiceLocator -
serviceObjName: jeffhanson.test:Name=HelloWorld,Type=GenericService
1156 [main] INFO com.jeffhanson.businesstier.services.HelloWorld -
Hello everybody!

当 servlet 引擎关闭 servlet,并调用 servlet 上的 destroy 方法时,servlet 会关闭 Geronimo 内核。当 servlet 引擎关闭 servlet 时,您控制台的输出结果应类似于 清单 8 所示。


清单 8. servlet 关闭后的输出结果
1156 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel  -
Starting kernel shutdown
1156 [main] DEBUG org.apache.geronimo.kernel.basic.BasicKernel -
Kernel shutdown complete

HelloWorld 类是带有 setMessage 方法、getMessage 方法和 sayHelloWorld 消息的简单 POJO。向 Geronimo 内核注册此类的实例后,您可以动态地调用该实例,并在运行时,使用依赖性注入将其与其他服务和组件关联。清单 9 中的代码说明了简单的 HelloWorld POJO 类。


清单 9. 简单的 HelloWorld 服务
package com.jeffhanson.businesstier.services;

import org.apache.log4j.Logger;

public class HelloWorld
{
private static Logger log = Logger.getLogger(HelloWorld.class);

private String message = "Hello world";

public void setMessage(String message)
{
if (message == null || message.length() <= 0)
{
throw new RuntimeException("HelloWorld.setMessage "
+ "param is not set");
}

this.message = message;
}

public String getMessage()
{
return message;
}

public void sayHello()
{
log.info(message);
}
}


blue_rule.gif
c.gif
c.gif
u_bold.gif回页首


结束语

设 计可以对业务更改和事件做出及时响应的敏捷而又有效的 SOA 是一项复杂的任务,但是,围绕适当设计的 POJO 层构建的 SOA 可以帮助简化这一任务。Geronimo 平台提供了框架和工具,您可以使用它通过 POJO 构建灵活的、可扩展的和可维护的 SOA。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130287/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/374079/viewspace-130287/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值