本文为原创,如需转载,请注明作者和出处,谢谢!
上一篇:
eclipse + JBoss 5 + EJB3开发指南(13):在Servlet中访问应用程序管制EntityManager对象
在前面的文章中给出的SessionBean的例子都是同步调用SessionBean方法的,也就是说,只有当方法中的代码都执行完,才能返回到客户端。但在某些情况下,由于SessionBean方法的执行时间比较长,这就需要异步地调用该方法,否则客户端就需要等待比较长的时间。要实现异步调用,就需要使用本要讲的消息驱动Bean。消息驱动Bean的基本原理是客户端向消息服务器发送一条消息后,消息服务器会将该消息保存在消息队列中。在这时消息服务器中的某个消费者(读取并处理消息的对象)会读取该消息,并进行处理。发送消息的客户端被称为消息生产者。
本文给出的消息驱动Bean的例子的基本功能是客户端向消息服务器发送一条消息(该消息实际上是一个实体Bean的对象实例),然后消息消费者读取这条消息后,将消息中的实体Bean持久化。实现消息驱动Bean的步骤如下:
一、实现实体Bean
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
package
entity;
import
java.io.Serializable;
import
java.util.Date;
import
javax.persistence.Column;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.Table;
@Entity @Table(name
=
"
t_date
"
)
public
class
DateBean
implements
Serializable {
private
int
id;
private
DatemyDate; @Id @GeneratedValue(strategy
=
GenerationType.IDENTITY)
public
int
getId() {
return
id; }
public
void
setId(
int
id) {
this
.id
=
id; } @Column(name
=
"
mydate
"
)
public
DategetMyDate() {
return
myDate; }
public
void
setMyDate(DatemyDate) {
this
.myDate
=
myDate; } }
二、编写消息驱动Bean
消息驱动Bean必须实现MessageListener接口,当该消息驱动Bean接收到一个消息后,EJB容器就会调用MessageListener接口的onMessage方法来理该消息。消息驱动Bean的代码如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
package
service;
import
javax.ejb.ActivationConfigProperty;
import
javax.ejb.EJBException;
import
javax.ejb.MessageDriven;
import
javax.jms.Message;
import
javax.jms.MessageListener;
import
javax.jms.ObjectMessage;
import
javax.persistence.EntityManager;
import
javax.persistence.PersistenceContext;
import
entity.DateBean;
@MessageDriven(activationConfig
=
{ @ActivationConfigProperty(propertyName
=
"
destinationType
"
,propertyValue
=
"
javax.jms.Queue
"
), @ActivationConfigProperty(propertyName
=
"
destination
"
,propertyValue
=
"
queue/MDBQueue
"
) })
public
class
DateMessageBean
implements
MessageListener { @PersistenceContext(unitName
=
"
myentity1
"
)
private
EntityManagerem; @Override
public
void
onMessage(Messagemessage) {
try
{
if
(message
instanceof
ObjectMessage) { ObjectMessageobjmsg
=
(ObjectMessage)message; DateBeandateBean
=
(DateBean)objmsg.getObject(); em.persist(dateBean); System.out.println(
"
成功持久化DateBean对象!
"
); }
else
{ System.out.println(
"
消息类型错误!
"
); } }
catch
(Exceptione) {
throw
new
EJBException(e); } } }
消息驱动Bean需要使用
@MessageDriven进行注释。要注意的是
destination
属性的值是
queue/MDBQueue。JBoss不会自已建立一个Queue对象,因此,需要手工来配置Queue对象。读者可以<JBoss5.x安装目录>\server\default\deploy目录中建立一个xxx-service.xml文件,其中xxx可以任意取值,但必须跟“-service”后缀,例如,abc-service.xml。该文件可以放在deploy或其子目录(可以是多层子目录)中。该文件的内容如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
<?
xmlversion="1.0"encoding="UTF-8"
?>
<
server
>
<
mbean
code
="org.jboss.mq.server.jmx.Queue"
name
="jboss.mq.destination:service=Queue,name=MDBQueue"
>
<
depends
optional-attribute-name
="DestinationManager"
>
jboss.mq:service=DestinationManager
</
depends
>
</
mbean
>
</
server
>
要注意的是,<mbean>元素的name属性值中的name必须是MDBQueue,要与queue/MDBQueue中的/后面的部分一致。如果不进行上面的配置,在启动JBOSS时就会抛出如下的异常:
javax.naming.NameNotFoundException: MDBQueue not bound
也可以将<mbean>元素放在deploy目录中的其他以-service.xml结尾的文件中。 如果不设置destination属性的值,在启动JBoss是会抛出如下的异常:org.jboss.deployers.spi.DeploymentException: Required config property RequiredConfigPropertyMetaData@174098f[name=destination descriptions=[DescriptionMetaData@4ca30b[language=zh]]] for messagingType 'javax.jms.MessageListener' not found in activation config [ActivationConfigProperty(destinationType=javax.jms.Queue), ActivationConfigProperty(connectionFactoryJndiName=MyQueueConnectionFactory), ActivationConfigProperty(destinationName=MyRequestQueue)] ra=jboss.jca:service=RARDeployment,name='jms-ra.rar' ... ...
三、编写调用消息驱动Bean的SessionBean
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
package
service;
import
java.util.ArrayList;
import
java.util.Date;
import
java.util.List;
import
javax.annotation.Resource;
import
javax.ejb.Stateless;
import
javax.jms.Connection;
import
javax.jms.ConnectionFactory;
import
javax.jms.MessageProducer;
import
javax.jms.ObjectMessage;
import
javax.jms.Queue;
import
javax.jms.Session;
import
javax.persistence.EntityManager;
import
entity.DateBean;
import
entity.Greeting;
@Stateless
public
class
GreeterBean
implements
Greeter {
@Resource(mappedName
=
"
ConnectionFactory
"
)
private
ConnectionFactorycf; @Resource(mappedName
=
"
queue/MDBQueue
"
)
private
Queuequeue;
@Override
public
Stringgreet(Stringmessage) {
try
{ DateBeandb
=
new
DateBean(); db.setMyDate(
new
Date()); Connectionconnection
=
cf.createConnection(); Sessionsession
=
connection.createSession(
false
,Session.AUTO_ACKNOWLEDGE); MessageProducermessageProducer
=
session.createProducer(queue); ObjectMessageobjectMessage
=
session.createObjectMessage(); objectMessage.setObject(db); messageProducer.send(objectMessage); connection.close(); System.out.println(
"
成功发送消息!
"
); }
catch
(Exceptione) { System.out.println(
"
发送消息失败!
"
); }
return
"
方法成功返回
"
;
} }
在上面的代码中使用ObjectMessage对象来包装要向消息服务器发送的实体Bean的对象实例。
除了可以在SessionBean中访问消息驱动Bean外,还可以在不同的机器上通过jndi来查找并调用消息驱动Bean,代码如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
package
test;
import
java.util.Date;
import
javax.ejb.EJB;
import
javax.jms.Destination;
import
javax.jms.MessageProducer;
import
javax.jms.ObjectMessage;
import
javax.jms.Queue;
import
javax.jms.QueueConnection;
import
javax.jms.QueueConnectionFactory;
import
javax.jms.QueueSession;
import
javax.jms.TextMessage;
import
javax.naming.InitialContext;
import
entity.DateBean;
import
service.Greeter;
public
class
Client {
public
static
void
main(String[]args)
throws
Exception {
InitialContextctx
=
new
InitialContext(); QueueConnectionconnection
=
null
; QueueSessionsession
=
null
; QueueConnectionFactoryfactory
=
(QueueConnectionFactory)ctx.lookup(
"
ConnectionFactory
"
); connection
=
factory.createQueueConnection(); session
=
connection.createQueueSession(
false
,QueueSession.AUTO_ACKNOWLEDGE); Destinationdestination
=
(Queue)ctx.lookup(
"
queue/MDBQueue
"
); MessageProducermessageProducer
=
session.createProducer(destination); ObjectMessageobjectMessage
=
session.createObjectMessage(); DateBeandb
=
new
DateBean(); db.setMyDate(
new
Date()); objectMessage.setObject(db); messageProducer.send(objectMessage); connection.close(); System.out.println(
"
成功发送消息!
"
); } }
下一篇:
eclipse + JBoss 5 + EJB3开发指南(15):拦截器方法和拦截器类
国内最棒的Google Android技术社区(eoeandroid),欢迎访问!
《银河系列原创教程》发布
《Java Web开发速学宝典》出版,欢迎定购
相关资源:垃圾分类数据集及代码