基于回调机制的异步日志服务的开发

时间:2022-10-09 08:50:45

基于回调机制的异步日志服务的开发

【摘要】日志服务作为软件开发中的一个重要组件,同步将带来额外的系统开销。本文介绍了一种利用回调机制开发异步日志服务的方法,有效地减少了系统性能的开销,提高了软件的健壮性。

【关键词】异步日志服务;回调机制;Hibernate

1.引言

在分布式计算环境中,通常使用传统的同步日志服务创建并发的客户端,分布式计算框架会部署到许多物理位置上完全不同的服务器上,在这种环境下,记录所有日志到中心数据库就显得相当繁琐——系统本身的调用阻塞会带来巨大的系统开销,使得日志服务几乎不可能完成。异步日志服务可有效的解决上述问题,在可靠模式(guaranteed mode)下,日志数据仅被提交一次到目的地便被Hibernate轻松的持久,减少了额外的系统开销,使客户端的业务执行更加流畅,较好地提高了软件的健壮性。

2.回调机制概述

软件模块之间的接口调用方式一般可分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种信息或发生某种事件时,会主动通知调用客户方的接口;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知,回调常常被认为是异步调用的基础。

图1 接口调用的三种方式

对于不同类型的语言、平台(Win32、

JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。

3.异步日志服务的框架

传统的同步日志模型中,日志服务调用没有成功返回前,调用者是不能往下执行的,所有的调用都被阻塞,直到记录被持久或被日志服务所接收。显然,当一个应用被设计用来记录大量的日志信息,每一条日志信息都必须在下一个日志被处理前完成记录,这将会是一个相当耗时处理过程。

一个通用的异步日志服务包括如下组件:客户端创建一个日志消息LogMessage

(Value Object),要求辅助类(JMSLogger)这个消息到队列;辅助类(JMSLoger)使用日志消息来创建一个JMS的Object Message,然后提交到队列Message Queue;一旦消息到达,容器就调用监听这个队列的MDB,访问它的onMessage回调方法;MDB读取消息(LogMessage),然后使用Hibernate持久消息到数据库。

因为可以把调用者与被调用者分开,调用者不再关心谁是被调用者,即客户端信任JMS的消息机制,从而无需考虑日志消息的传送过程。日志服务使用JMS的点对点消息方式,保证了消息被可靠地投递。图2说明了一个通用的异步日志服务的主要框架组件。

图2 日志服务的功能框架图

4.开发实例

下面通过一个实例来展示回调机制在开发一个简单的异步日志服务中的应用。本实例的主要流程是:创建一些日志信息,通过网络发送到JMS提供者,并且持久到数据库。为达到这个目的,本例中使用JMS来实现异步、访问onMessage实现回调、使用Hibernate来持久数据。图3是JMS API Programming Model的模型示意图[1]。

图3.JMS对象模型

回调机制的基本思想就是调用者在初始化一个对象时,将一些参数传递给对象,同时将一个调用者可以访问的函数地址传递给该对象。这个函数就是调用者和被调用者之间的一种通知约定,当约定的事件发生时,被调用者就会按照回调函数地址调用该函数。下面展示开发实例:

not-null="false"/>

not-null="false"/>

not-null="false"/>

3、回调

private void persistMessage(LogMessage message) throws

HibernateException {

net.sf.hibernate.Session session = null;

SessionFactory sessionFactory = null;

Transaction tx = null;

try {

// Create a session factory from the configuration

(hibernate.properties

// File should be present in the class path)

sessionFactory = new Configuration(). addClass(LogMessage.class).

buildSessionFactory();

// Create a session

session = sessionFactory.openSession();

// Begin a transaction

tx = session.beginTransaction ();

}catch(..){

.....

}

try{

// Assign the message id

message.setMessageId (""+System.currentTimeMillis ());

// Save the object to the database and commit the transaction

session.save(message);

mit ();

}catch(Exception ex){

....

}finally {

// Close the session

session.close();

}

}

4、实现日志持久

sessionFactory = new Configuration().

addClass(LogMessage.class).

buildSessionFactory();

session = sessionFactory.openSession();

tx = session.beginTransaction ();

…………………

message.setMessageId (""+System.currentTimeMillis ());

// Save the object to the database.

session.save(message);

mit ();

正如我们所看到的,一旦确定对象的关系映射文件,持久的日志信息将会很容易地进入到数据库中,而hibernate将在后台处理好一切相关的工作。本实例的开发包括三个清晰的开发步骤:

第一步:创建应用入口。

日志程序是这个应用的入口点,日志程序使用JMSLogger发送消息到队列,它创建一个日志消息(LogMessage),然后由JMSLogger发送到LogMessageQueue目的地JMSLogger是一个JMS类,一旦被实例化,它就关联自己到消息目的地。因此,当JMSLogger被日志程序创建,它就通过JNIDI命名空间查找连接工厂(Connection Factory)和队列(Queue),然后开启和JMS提供者(JMS Provider)的会话(Session),

第二步:实现回调。

接下来,JMSLogger发送消息到目的地。应用客户端通过简单的实例化日志程序和调用它的方法来访问日志服务。在J2EE环境下,日志服务只在应用服务启动的时候被实例化一次,当应用服务启动时,使用Java管理扩展来管理Beans,这样客户端便能通过JNDI查找到这个服务,然后像往常一样,调用它的方法来持久日志消息。

第三步:实现日志持久。

LogMessageQueue是日志消息发送的目的地,一个MDB监听这个队列。一旦消息到达队列,EJB容器就调用MDB,并且委派它作更多的处理。MDB取出日志消息(LogMessage),通过Hiberante的持久机制,持久日志消息到数据库。

5.结语

利用回调机制开发的异步日志服务,提供了许多其他分布式对象计算模型没有的优点,如:日志产生者和调用者之间的“松耦合”,系统的高可扩展性,以及高度的可靠性。上述优势的存在,解决了同步日志系统中存在的代码混乱、紧耦合和执行效率低下等问题,它还有具有一些别的好处:对于使用者,消息的产生、传递是透明的[2]。这就为建立动态的、可靠的和灵活的应用系统提供了很好的组件。比如,日志服务是许多应用程序的基础,这些应用程序可以是工作流,网络管理,通信服务或供应链管理程序等。

参考文献

[1]何文涛,冯勇卫.中间件服务器上MDB持久化消息的探讨[J].微电子学与计算机,2008(04).

[2]曾斌,彭长根,杨辉,等.基于J2EE技术的企业异步通信解决方案[J].计算机工程,2006(05).

作者简介:叶小莺(1980—),湖南长沙人,助教,主要从事计算机教学及教学管理工作。

上一篇:吉兆GME3011型电视激励器内置开关电源原理与检... 下一篇:基于DSP的测量数据预处理