EJB中的消息驱动bean(MessageDrivenBean,MDB)是设计用来专门处理基于消息请求的组件。一个MDB类必须实现MessageListener接口,当容器检测到bean 守候的队列的一条消息时,就调用onMessage() 方法,将消息作为参数传入。 什么时候使用消息驱动Bean?
1)当一个业务方法需要很长时间处理,而处理时间不确定
2)客户端调用后无需服务器立刻返回结果
EJB中消息驱动Bean(MessageDrivenBean,MDB),其典型代表是JMS(Java Message Service)的实现。
JMS 支持两种消息模型:
PTP(Point-to-Point) 消息传递模型规定了一条消息只能传递给一个接收方。
Pub/sub(Publish/Subscribe)消息传递模型允许一条消息传递给多个接收方。
消息驱动bean 实际上就是一个异步的JMS 消费者,而这个消费者一般做以下2件事
1)通过实现 onMessage() 方法来获取消息目的的消息对象
2)通过业务逻辑EJB 组件,对获取的信息执行业务逻辑
在EJB容器中,和SessionBean一样都是有一个对象池来维护消息驱动bean的生命周期的。
实例代码:
1、我们在Weblogic的控制台上配置一个新的Queue 类型的JMS 消息目的,其JNDI名称为queue
步骤:
① 配置持久化存储
② 配置JMS服务器
③ 配置JMS模块
④ 为JMS模块配置子部署
⑤ 配置消息目的地
详情可参考:JMS配置过程图解
2、代码实例
1)我们需要在服务器端开发消息驱动Bean和消息驱动Bean相关的类
TempDTO 类代表了 temp 表的实体
package ejb.message.dto;
import java.io.Serializable;
public class TempDTO implements Serializable
{
private static final long serialVersionUID = -7614295090818744529L;
private int id;
private String name;
private String address;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
}
懒得写接口了,我直接写处理实体的业务类TempServic
package ejb.sessionbean;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.sql.DataSource;
import ejb.message.dto.TempDTO;
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TempService
{
@Resource(mappedName="MySqlDs")
private DataSource dataSource;
@Resource
private SessionContext sessionContext;
public boolean insertTemp(TempDTO temp)
{
if(temp ==null || temp.getName() == null)
{
return false;
}
Connection conn = null;
Statement stmt = null;
try
{
conn = dataSource.getConnection();
stmt = conn.createStatement();
StringBuffer sql = new StringBuffer("insert into temp values(");
sql.append(temp.getId()).append(",'");
sql.append(temp.getName()).append("','");
sql.append(temp.getAddress()).append("')");
System.out.println(sql.toString());
stmt.executeUpdate(sql.toString());
stmt.close();
conn.close();
return true;
}
catch (SQLException e)
{
System.out.println("事务回滚");
sessionContext.setRollbackOnly();
e.printStackTrace();
return false;
}
}
}
消息驱动bean ,该类可能有错误,连接Weblogic中的jms 的注解该如何写呢?
需要重点说明的注解:@MessageDriven
@MessageDriven 注解有activationCofig 属性配置,它是对该驱动bean监听的JMS消息的一些配置西你想,使用@ActivationConfigProperty注解作为配置项,每个配置项都是由propertyName和propertyValue这种键值对儿作为属性的配置。 1):destinationType:表示消费目的类型,是PTP类型或者定制
acknowledgeMode:JMS消息的确认模式,是否回复,还是自动回复
destination:表示监听的消息目的JNDI名,此属性只对JBoss容器生效
mappedName:指定消息驱动Bean监听的消息目的,此属性配置对于Weblogic、Glassfish生效。
package ejb.message;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.Stateless;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import ejb.message.dto.TempDTO;
import ejb.sessionbean.TempService;
@Stateless(mappedName="queue")
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
})
public class TempDTOMessageDrivenBean implements MessageListener
{
@EJB(beanName = "TempService")
private TempService tempService;
@Override
public void onMessage(Message msg)
{
if (msg != null)
{
if (msg instanceof ObjectMessage)
{
ObjectMessage objmsg = (ObjectMessage)msg;
TempDTO temp;
try
{
temp = (TempDTO)objmsg.getObject();
tempService.insertTemp(temp);
System.out.println("执行插入业务完毕");
}
catch (JMSException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
至此,可以说MDB 已经完成,只差部署在Weblogic服务器上,然后使用客户端去访问该EJB即可。但是,实际上我的测试并不成功,我始终都不明白这里,如果是把写好的EJB重新部署到了服务器上,那么这与JMS 又是通过什么关联的呢?
客户端访问
package ejb.messageDrivenBean.dto;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import ejb.message.dto.TempDTO;
public class MessageSender
{
public static void main(String[] args)
{
try
{
Hashtable cs = new Hashtable();
cs.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
cs.put(Context.PROVIDER_URL, "t3://localhost:7001");
InitialContext ctx = new InitialContext(cs);
//获取ConnectionFactory对象
QueueConnectionFactory factory = (QueueConnectionFactory)ctx.lookup("weblogic.jms.ConnectionFactory");
System.out.println(factory.toString()+" 连接工厂");
//创建QueueConnection对象
QueueConnection connection = factory.createQueueConnection();
//创建QueueSession对象,第一个参数表示事务自动提交,第二个参数标识一旦消息被正确送达,将自动发回响应
QueueSession session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
//获得Destination对象
Queue queue = (Queue)ctx.lookup("queue");
//创建文本消息
//TextMessage msg = session.createTextMessage("世界,你好");
//创建发送者
QueueSender sender = session.createSender(queue);
// 创建对象消息
ObjectMessage msg = session.createObjectMessage();
TempDTO temp = new TempDTO();
temp.setName("xiaoming");
temp.setAddress("光谷");
msg.setObject(temp);
//发送消息
sender.send(msg);
System.out.println("end");
//关闭会话
session.close();
}
catch (NamingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (JMSException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
后记:
我将前面的EJB部署在Weblogic 上,然后执行客户端类,没有得到预期中的结果。
有几个我不确定的地方:
1) EJB 的部署方法真的像我理解的这样部署吗?具体见: EJB 中 Session Bean 的部署与实现
2) 消息驱动bean 与 JMS的JNDI 相关联的注解该怎么写呢?
3) 该怎样调测服务器上的EJB 可以正常的执行呢?
注:以上代码功能未调测通过,无实际意义。