JavaEE5学习笔记06-EJB之消息驱动Bean(MDB)总结----2
除了activationConfig之外,如果使用其他JavaEE容器,比如Weblogic、Glassfish等等,还得加上如下几个注解配置项。
mappedName:指定消息驱动Bean监听的消息目的,此属性配置对于Weblogic、Glassfish生效。
messageListener:如果该消息驱动类没有在代码中显示的实现接口MessageListener的话就需要在此属性配置中加上实现的接口类。
在这个消息驱动Bean中接收到的消息是一个ObjectMessage类型的消息,前面JMS总结章节说过ObjectMessage是一个实现了Serializable接口的实体对象,这里实际上指的就是UserDTO对象。
在这个消息驱动Bean中还调用了一个SessionBean,它的代码如下(接口类不再赘述):
?/**
?* 容器管理事务的用户添加的SessionBean
?*
?* @author liuyan
?*
?*/
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class UserServiceEAOImpl implements UserService {
?
????? /**
????? ?* 资源注入
????? ?*/
????? @Resource(mappedName = "java:/jbossdemo")
????? private DataSource dataSource;
?
????? @Resource
????? private SessionContext sessionContext;
?
????? /**
????? ?* 添加方法实现
????? ?*/
????? @Override
????? public boolean insertUser(UserDTO userDTO) {
?
???????????? if (userDTO == null || userDTO.getId() == 0
?????????????????????????? || userDTO.getName() == null) {
??????????????????? return false;
???????????? }
?
???????????? Connection connection = null;
?
???????????? Statement statement = null;
?
???????????? try {
?
??????????????????? connection = dataSource.getConnection();
?
??????????????????? statement = connection.createStatement();
?
??????????????????? StringBuffer insertSQL = new StringBuffer(
????????????????????????????????? "insert into person values(");
?
??????????????????? insertSQL.append(userDTO.getId()).append(",'").append(
????????????????????????????????? userDTO.getName()).append("')");
?
??????????????????? System.out.println("SQL::" + insertSQL.toString());
?
??????????????????? statement.executeUpdate(insertSQL.toString());
?
??????????????????? statement.close();
??????????????????? connection.close();
??????????????????? return true;
???????????? } catch (Exception e) {
??????????????????? System.out.println("事务回滚~~");
??????????????????? sessionContext.setRollbackOnly();
??????????????????? e.printStackTrace();
??????????????????? return false;
???????????? }
?
????? }
}
这是一个很简单的根据实体对象执行插入数据库的业务逻辑。万事俱备,只欠消息生产者,我们的消息生产者和之前JMS的消息生产者内容差不多。
package ejb.messageDrivenBean;
??
/**
?* 消息发送者
?*
?* @author liuyan
?*
?*/
public class JbossMessageSender {
?
??? /**
??? ?* 发送消息
??? ?*
??? ?* @throws Exception
??? ?*/
??? public void sendMessage() {
?
?????? try {
?????????? String Connection_Factory = "ConnectionFactory";
?
?????????? Context context = getInitialContext();
?
?????????? ConnectionFactory connectionFactory = (ConnectionFactory) context
????????????????? .lookup(Connection_Factory);
?
?????????? Destination dest = (Destination) context.lookup("InsertUserQueue");
?
?????????? Connection connection = connectionFactory.createConnection();
?
?????????? Session session = connection.createSession(false,
????????????????? Session.AUTO_ACKNOWLEDGE);
?
?????????? MessageProducer sender = session.createProducer(dest);
?
?????????? sender.setDeliveryMode(DeliveryMode.PERSISTENT);
?????????? sender.setTimeToLive(2000);
?
?????????? // 获得ObjectMessage对象
?????????? ObjectMessage objectMessage = session.createObjectMessage();
?
?????????? // 构建参数
?????????? UserDTO userDTO = new UserDTO();
?????????? userDTO.setId(19);
?????????? userDTO.setName("乱世狂刀");
?
?????????? objectMessage.setObject(userDTO);
?
?????????? sender.send(objectMessage);
?
?????????? session.close();
?????????? connection.close();
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
?
??? }
?
??? private Context getInitialContext() {
?????? String init_factory = "org.jnp.interfaces.NamingContextFactory";
?????? String serverURL = "jnp://127.0.0.1:1099";
?????? Context context = null;
?
?????? Properties properties = new Properties();
?????? properties.put(Context.INITIAL_CONTEXT_FACTORY, init_factory);
?????? properties.put(Context.PROVIDER_URL, serverURL);
?????? try {
?????????? context = new InitialContext(properties);
?????? } catch (NamingException e) {
?????????? // TODO Auto-generated catch block
?????? ??? e.printStackTrace();
?????? }
?????? return context;
?
??? }
?
??? /**
??? ?* @param args
??? ?* @throws Exception
??? ?*/
??? public static void main(String[] args) throws Exception {
?
?????? JbossMessageSender jbossMessageSender = new JbossMessageSender();
?????? jbossMessageSender.sendMessage();
??? }
?
}
开启JBoss服务器后,在另一个JVM中运行消息生产者程序后,发现数据库已经插入了一条记录
?
由此观之,这是一个通过JMS发送消息来引发的一个插入数据的事件的过程。过程如下描述:
启动JBoss——》消息消费者(消息驱动Bean)随着JBoss启动而被容器创建在容器对象池中——》消息将消费者监听消息目的——》JMS生产一个消息——》将实体对象一同发送到消息目的——》消息驱动Bean监听到了消息目的有消息了——》调用onMessage方法获取消息——》根据获取的消息进行强制转型(一般是业务实体)——》调用被注入的SessionBean组件方法执行业务逻辑——》完毕,消息驱动Bean归还给对象池。
实际上了解了JMS的使用原理后,配合消息驱动Bean开发应该不是很难。总之,消息驱动Bean是一个异步消费者。所以要实现特定接口MessageListener和特定方法onMessage()。还有就是消息驱动的注解配置属性可能相对于SessionBean来说有点多。还有就是消息驱动Bean的使用时机,一般是不要求客户端立刻获得执行结果的情况和在一般执行相对较长时间的业务情况。所以上面的实例代码其实不是真正的实际应用场景,而只是一个Demo罢了。多谢~~~~~夜深!!!