JavaEE5学习笔记06EJB之消息驱动Bean总结.docx
- 文档编号:11214035
- 上传时间:2023-02-25
- 格式:DOCX
- 页数:12
- 大小:157.34KB
JavaEE5学习笔记06EJB之消息驱动Bean总结.docx
《JavaEE5学习笔记06EJB之消息驱动Bean总结.docx》由会员分享,可在线阅读,更多相关《JavaEE5学习笔记06EJB之消息驱动Bean总结.docx(12页珍藏版)》请在冰豆网上搜索。
JavaEE5学习笔记06EJB之消息驱动Bean总结
JavaEE5学习笔记06-EJB之消息驱动Bean总结
刘岩
Email:
suhuanzheng7784877@
1.功能介绍
在EJB的分类中还有一个就是消息驱动Bean(MessageDrivenBean),XX的说明其实很到位。
消息驱动Bean(MDB)是设计用来专门处理基于消息请求的组件。
一个MDB类必须实现MessageListener接口。
当容器检测到bean守候的队列一条消息时,就调用onMessage()方法,将消息作为参数传入。
MDB在OnMessage()中决定如何处理该消息。
你可以用注释来配置MDB监听哪一条队列。
当MDB部署时,容器将会用到其中的注释信息。
当一个业务执行的时间很长,而执行结果无需实时向用户反馈时,很适合使用消息驱动Bean。
如订单成功后给用户发送一封电子邮件或发送一条短信等。
消息驱动bean是一个异步消息使用者。
当JMS消息到达时,容器激发消息驱动bean。
消息驱动bean既没有本地接口也没有组件接口。
消息驱动bean实例是一个消息驱动bean类的实例。
对客户机来说,消息驱动bean是一个在服务器上实现某些业务逻辑的JMS消息使用者。
客户机通过JMS发送消息到JMSDestination(Queue或Topic)来访问消息驱动bean,而消息驱动bean类是JMSDestination的MessageListener。
消息驱动bean实例没有会话状态。
这意味着当不涉及服务客户机消息时,所有的bean实例都是等同的。
消息驱动bean是匿名的。
它们没有客户机可视的标识。
容器创建消息驱动bean实例来进行消息处理,而消息驱动bean是这些消息的使用者。
其生命周期由容器控制。
消息驱动bean实例没有特定于客户机的状态。
然而,通过处理客户机信息,消息驱动bean实例的实例变量可以包含状态。
这些状态的示例包括一个开放的数据库连接和一个EJB对象的对象引用。
其实核心的问题就是我们什么情况下使用消息驱动Bean
1):
当一个业务方法需要很长时间处理的时候,而且处理时间十分不确定
2):
客户端调用后无需服务端立刻返回结果
而我们在这里不得不再说一下,消息驱动Bean实际上就是一个异步的JMS消费者。
而这个消费者一般需要做以下2件事情就够了。
1):
通过实现onMessage()方法来获取消息目的的消息对象
2):
调用业务逻辑EJB组件,对获取的信息执行业务逻辑
在EJB容器中,和SessionBean一样都是有一个对象池来维护消息驱动Bean的生命周期的。
2.实例代码
首先我们在JBoss的控制台上配置一个新的Queue类型的JMS消息目的,如下所示:
如上所示,在JBoss中新增了一个叫做InsertUserQueue的消息目的。
下面我们在服务器端开发消息驱动Bean以及和消息驱动Bean有关的类。
UserDTO类代表了表person的实体
packageejb.messageDrivenBean.dto;
importjava.io.Serializable;
/**
*表person的数据模型
*@authorliuyan
*
*/
publicclassUserDTOimplementsSerializable{
/**
*
*/
privatestaticfinallongserialVersionUID=-4153158445872587565L;
privateintid;
privateStringname;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
真正的消息驱动Bean
packageejb.messageDrivenBean;
importjavax.ejb.ActivationConfigProperty;
importjavax.ejb.EJB;
importjavax.ejb.MessageDriven;
importjavax.jms.JMSException;
importjavax.jms.Message;
importjavax.jms.MessageListener;
importjavax.jms.ObjectMessage;
importejb.messageDrivenBean.dto.UserDTO;
importejb.sessionBean.UserService;
/**
*消息驱动Bean
*
*@authorliuyan
*/
@MessageDriven(activationConfig={
@ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="acknowledgeMode",propertyValue="Auto-acknowledge"),
@ActivationConfigProperty(propertyName="destination",propertyValue="InsertUserQueue")})
publicclassUserDTOMessageDrivenBeanimplementsMessageListener{
/**
*注入其他EJB组件
*/
@EJB(beanName="UserServiceEAOImpl")
privateUserServiceuserService;
/**
*消息接到后的处理方法
*/
@Override
publicvoidonMessage(Messagemessage){
//TODOAuto-generatedmethodstub
if(message!
=null){
if(messageinstanceofObjectMessage){
//获得消息
ObjectMessageobjectMessage=(ObjectMessage)message;
try{
//强制转型
UserDTOuserDTO=(UserDTO)objectMessage.getObject();
//插入数据
userService.insertUser(userDTO);
System.out.println("执行插入业务完毕");
}catch(JMSExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
}
}
这个类是真正的消息驱动Bean,这里需要说明的就是此类必须实现接口MessageListener以及它的onMessage方法,在方法中会获得消息目的的消息,从而进行消息的消费。
此处是调用了一个被注入的EJB组件——SessionBean。
还有一个需要重点说明的就是@MessageDriven注解,@MessageDriven注解有activationConfig属性配置,它是对该驱动Bean监听的JMS消息的一些配置信息,使用@ActivationConfigProperty注解作为配置项,每个配置项都是由propertyName和propertyValue这种键值对儿作为属性的配置。
1):
destinationType:
表示消费目的类型,是PTP类型或者定制
2):
acknowledgeMode:
JMS消息的确认模式,是否回复,还是自动回复
3):
destination:
表示监听的消息目的JNDI名,此属性只对JBoss容器生效
除了activationConfig之外,如果使用其他JavaEE容器,比如Weblogic、Glassfish等等,还得加上如下几个注解配置项。
mappedName:
指定消息驱动Bean监听的消息目的,此属性配置对于Weblogic、Glassfish生效。
messageListener:
如果该消息驱动类没有在代码中显示的实现接口MessageListener的话就需要在此属性配置中加上实现的接口类。
在这个消息驱动Bean中接收到的消息是一个ObjectMessage类型的消息,前面JMS总结章节说过ObjectMessage是一个实现了Serializable接口的实体对象,这里实际上指的就是UserDTO对象。
在这个消息驱动Bean中还调用了一个SessionBean,它的代码如下(接口类不再赘述):
packageejb.sessionBean.impl;
importjava.sql.Connection;
importjava.sql.Statement;
importjavax.annotation.Resource;
importjavax.ejb.SessionContext;
importjavax.ejb.Stateless;
importjavax.ejb.TransactionAttribute;
importjavax.ejb.TransactionAttributeType;
importjavax.ejb.TransactionManagement;
importjavax.ejb.TransactionManagementType;
importjavax.sql.DataSource;
importejb.messageDrivenBean.dto.UserDTO;
importejb.sessionBean.UserService;
/**
*容器管理事务的用户添加的SessionBean
*
*@authorliuyan
*
*/
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
publicclassUserServiceEAOImplimplementsUserService{
/**
*资源注入
*/
@Resource(mappedName="java:
/jbossdemo")
privateDataSourcedataSource;
@Resource
privateSessionContextsessionContext;
/**
*添加方法实现
*/
@Override
publicbooleaninsertUser(UserDTOuserDTO){
if(userDTO==null||userDTO.getId()==0
||userDTO.getName()==null){
returnfalse;
}
Connectionconnection=null;
Statementstatement=null;
try{
connection=dataSource.getConnection();
statement=connection.createStatement();
StringBufferinsertSQL=newStringBuffer(
"insertintopersonvalues(");
insertSQL.append(userDTO.getId()).append(",'").append(
userDTO.getName()).append("')");
System.out.println("SQL:
:
"+insertSQL.toString());
statement.executeUpdate(insertSQL.toString());
statement.close();
connection.close();
returntrue;
}catch(Exceptione){
System.out.println("事务回滚~~");
sessionContext.setRollbackOnly();
e.printStackTrace();
returnfalse;
}
}
}
这是一个很简单的根据实体对象执行插入数据库的业务逻辑。
万事俱备,只欠消息生产者,我们的消息生产者和之前JMS的消息生产者内容差不多。
packageejb.messageDrivenBean;
importjava.util.Properties;
importjavax.jms.Connection;
importjavax.jms.ConnectionFactory;
importjavax.jms.DeliveryMode;
importjavax.jms.Destination;
importjavax.jms.MessageProducer;
importjavax.jms.ObjectMessage;
importjavax.jms.Session;
importjavax.naming.Context;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;
importejb.messageDrivenBean.dto.UserDTO;
/**
*消息发送者
*
*@authorliuyan
*
*/
publicclassJbossMessageSender{
/**
*发送消息
*
*@throwsException
*/
publicvoidsendMessage(){
try{
StringConnection_Factory="ConnectionFactory";
Contextcontext=getInitialContext();
ConnectionFactoryconnectionFactory=(ConnectionFactory)context
.lookup(Connection_Factory);
Destinationdest=(Destination)context.lookup("InsertUserQueue");
Connectionconnection=connectionFactory.createConnection();
Sessionsession=connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducersender=session.createProducer(dest);
sender.setDeliveryMode(DeliveryMode.PERSISTENT);
sender.setTimeToLive(2000);
//获得ObjectMessage对象
ObjectMessageobjectMessage=session.createObjectMessage();
//构建参数
UserDTOuserDTO=newUserDTO();
userDTO.setId(19);
userDTO.setName("乱世狂刀");
objectMessage.setObject(userDTO);
sender.send(objectMessage);
session.close();
connection.close();
}catch(Exceptione){
e.printStackTrace();
}
}
privateContextgetInitialContext(){
Stringinit_factory="org.jnp.interfaces.NamingContextFactory";
StringserverURL="jnp:
//127.0.0.1:
1099";
Contextcontext=null;
Propertiesproperties=newProperties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,init_factory);
properties.put(Context.PROVIDER_URL,serverURL);
try{
context=newInitialContext(properties);
}catch(NamingExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
returncontext;
}
/**
*@paramargs
*@throwsException
*/
publicstaticvoidmain(String[]args)throwsException{
JbossMessageSenderjbossMessageSender=newJbossMessageSender();
jbossMessageSender.sendMessage();
}
}
开启JBoss服务器后,在另一个JVM中运行消息生产者程序后,发现数据库已经插入了一条记录
由此观之,这是一个通过JMS发送消息来引发的一个插入数据的事件的过程。
过程如下描述:
启动JBoss——》消息消费者(消息驱动Bean)随着JBoss启动而被容器创建在容器对象池中——》消息将消费者监听消息目的——》JMS生产一个消息——》将实体对象一同发送到消息目的——》消息驱动Bean监听到了消息目的有消息了——》调用onMessage方法获取消息——》根据获取的消息进行强制转型(一般是业务实体)——》调用被注入的SessionBean组件方法执行业务逻辑——》完毕,消息驱动Bean归还给对象池。
3.总结
实际上了解了JMS的使用原理后,配合消息驱动Bean开发应该不是很难。
总之,消息驱动Bean是一个异步消费者。
所以要实现特定接口MessageListener和特定方法onMessage()。
还有就是消息驱动的注解配置属性可能相对于SessionBean来说有点多。
还有就是消息驱动Bean的使用时机,一般是不要求客户端立刻获得执行结果的情况和在一般执行相对较长时间的业务情况。
所以上面的实例代码其实不是真正的实际应用场景,而只是一个Demo罢了。
多谢~~~~~夜深!
!
!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JavaEE5 学习 笔记 06 EJB 消息 驱动 Bean 总结