1. MDB作为异步消费者的本质

2. MDB的运行机制

3. 使用@MessageDriven修饰MDB(需要messageListenerInterface)

4. 实现MessageListener

5. MDB的生命周期

6. 在MDB中使用依赖注入

7. MDB中的事务管理和异常管理

------------------------------------------------

1. MDB作为异步消费者的本质

MDB存在于EJB容器之中,可以利用EJB提供的事务、安全和并发性等系统服务。MDB并不直接与客户端交互,只是一个JMS消息的异步消费者。

EAO: Entiry Access Object

2. MDB的运行机制

MDB是由无状态Session Bean变化而来的,因此在用法上与其相似,不会保存客户端的调用状态,可被多个客户端共享。客户端需要以同步方式来调用无状态Session Bean,MDB不允许直接调用,它只是一个消息监听者。

消息生产者(发送消息)-->JMS消息目的(触发onMessage()方法)-->MDB(调用业务方法)-->Session Bean

3. 使用@MessageDriven修饰MDB

#1. EJB开发(Net Beans创建EJB Module, 项目名称:SimpleMDB)

SimpleMDB.java

package org.crazyit.jms;

import javax.ejb.*;
import javax.jms.*;

@MessageDriven(activationConfig
        = {
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "MessageQueue")
        } , 
        messageListenerInterface = javax.jms.MessageListener.class, 
        mappedName = "MessageQueue"
)
public class SimpleMDB {

    public void onMessage(Message msg) {
        try {
            if (msg instanceof TextMessage) {
                TextMessage txt = (TextMessage) msg;
                String content = txt.getText();
                System.out.println("JMS信息中信息为:" + content);
            }
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

 

#2. 消息发送(Net Beans创建Java Project, 项目名称:SendMsg)

SendMsg.java

package lee;

import javax.jms.*;
import javax.naming.*;
import java.util.Properties;

public class SendMsg {

    public void sendMessage() throws NamingException, JMSException {
        //定义WebLogic默认连接工厂的JNDI
        final String CONNECTION_FACTORY_JNDI = "weblogic.jms.ConnectionFactory";
        //获取JNDI服务所需的Context
        Context ctx = getInitialContext();
        //通过JNDI查找获取连接工厂
        ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup(CONNECTION_FACTORY_JNDI);
        //通过JNDI查找获取消息目的
        Destination dest = (Destination) ctx.lookup("MessageQueue");
        //连接工厂创建连接
        Connection conn = connFactory.createConnection();
        //JMS连接创建JMS会话
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //JMS会话创建消息生产者
        MessageProducer sender = session.createProducer(dest);
        //设置消息生产者生产出来的消息的传递模式、有效时间。
        sender.setDeliveryMode(DeliveryMode.PERSISTENT);
        sender.setTimeToLive(20000);
        //通过JMS会话创建一个文本消息
        TextMessage msg = session.createTextMessage();
      //msg.setStringProperty("ConType","txt");
        //设置消息内容
        msg.setText("Hello");
        //发送消息
        sender.send(msg);
        msg.setText("Welcome to JMS");
        //再次发送消息
        sender.send(msg);
        //关闭资源
        session.close();
        conn.close();
    }

    //工具方法,用来获取命名服务的Context对象
    private Context getInitialContext() {
        // 参见(4)
    }

    public static void main(String[] args) throws Exception {
        SendMsg sender = new SendMsg();
        sender.sendMessage();
    }
} 

SendMapMsg.java

package lee;

import javax.jms.*;
import javax.naming.*;
import java.util.Properties;

public class SendMapMsg {

    public void sendMessage() throws NamingException, JMSException {
        //定义WebLogic默认连接工厂的JNDI
        final String CONNECTION_FACTORY_JNDI = "weblogic.jms.ConnectionFactory";
        //获取JNDI服务所需的Context
        Context ctx = getInitialContext();
        //通过JNDI查找获取连接工厂
        ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup(CONNECTION_FACTORY_JNDI);
        //通过JNDI查找获取消息目的
        Destination dest = (Destination) ctx.lookup("MessageQueue");
        //连接工厂创建连接
        Connection conn = connFactory.createConnection();
        //JMS连接创建JMS会话
        Session session = conn.createSession(false/*不是事务性会话*/, Session.AUTO_ACKNOWLEDGE);
        //JMS会话创建消息生产者
        MessageProducer sender = session.createProducer(dest);
        //设置消息生产者生产出来的消息的传递模式、有效时间。
        sender.setDeliveryMode(DeliveryMode.PERSISTENT);
        sender.setTimeToLive(20000);
        //通过JMS会话创建一个文本消息
        MapMessage msg = session.createMapMessage();
        //设置消息内容
        msg.setString("name", "孙悟空");
        msg.setString("gender", "男");
        msg.setInt("age", 500);
        //发送消息
        sender.send(msg);
        //关闭资源
        session.close();
        conn.close();
    }

    //工具方法,用来获取命名服务的Context对象
    private Context getInitialContext() {
        // 参见(4)
    }

    public static void main(String[] args) throws Exception {
        SendMapMsg sender = new SendMapMsg();
        sender.sendMessage();
    }
}

4. 实现MessageListener

#1. EJB开发(Net Beans创建EJB Module, 项目名称:SimpleMDBListener)

SimpleMDB.java

package org.crazyit.jms;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(activationConfig ={
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "MessageQueue")
        },
     mappedName = "MessageQueue" )
public class SimpleMDB implements MessageListener { @Override public void onMessage(Message msg) { try { if (msg instanceof TextMessage) { TextMessage txt = (TextMessage) msg; String content = txt.getText(); System.out.println("JMS信息中信息为:" + content); } } catch (Exception ex) { ex.printStackTrace(); } } }

5. MDB的生命周期

#1. EJB开发(Net Beans创建EJB Module, 项目名称:Lifecycle)

LifecycleMDB.java

package org.crazyit.jms;

import javax.ejb.*;
import javax.jms.*;
import javax.annotation.*;

@MessageDriven(activationConfig
        = {
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "MessageQueue")
        }, 
        mappedName = "MessageQueue"
)
public class LifecycleMDB implements MessageListener {

    public void onMessage(Message msg) {
        try {
            if (msg instanceof TextMessage) {
                TextMessage txt = (TextMessage) msg;
                String content = txt.getText();
                System.out.println("JMS信息中信息为:" + content);
            }
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @PostConstruct
    public void myInit() {
        System.out.println("--初始化方法--");
    }

    @PreDestroy
    public void myDestroy() {
        System.out.println("--销毁之前的方法--");
    }
}

6. 在MDB中使用依赖注入

#1. EJB开发(Net Beans创建EJB Module, 项目名称:Injection)

Injection.java

package org.crazyit.jms;

import javax.ejb.*;
import javax.jms.*;

import org.crazyit.service.*;

@MessageDriven(activationConfig
        = {
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "MessageQueue")
        }, 
        mappedName = "MessageQueue"
)
public class Injection implements MessageListener {

    @EJB(name = "StudentBean")
    private Student student;

    public void onMessage(Message msg) {
        try {
            if (msg instanceof MapMessage) {
                MapMessage map = (MapMessage) msg;
                String name = map.getString("name");
                String gender = map.getString("gender");
                int age = map.getInt("age");
                //调用Session Bean的方法添加学生。
                student.add(name, gender, age);
            }
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Student.java

package org.crazyit.service;

import javax.ejb.*;

@Remote
public interface Student {
    void add(String name, String gender, int age) throws Exception;
}

StudentBean.java

package org.crazyit.service;

import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.annotation.*;

@Stateless(name = "StudentBean")
public class StudentBean implements Student {

    //采用依赖注入获取数据源
    @Resource(name = "javaee")
    private DataSource ds;

    public void add(String name, String gender, int age) throws Exception {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            //通过数据源获取数据库连接
            conn = ds.getConnection();
            //使用PreparedStatement执行SQL语句
            pstmt = conn.prepareStatement("insert into student values(null , ? , ? , ?)");
            pstmt.setString(1, name);
            pstmt.setString(2, gender);
            pstmt.setInt(3, age);
            pstmt.executeUpdate();
        } 
        finally {
            pstmt.close();
            conn.close();
        }
    }
}
View Code

7. MDB中的事务管理和异常管理

MDB同样支持CMT和BMT,使用CMT,采用如下两种Annotation来修饰MDB的Bean实现类或方法:

@TransactionManagement:配置事务管理类型

@TransactionAttribute:配置事务管理属性

如果希望CMT事务管理机制遇到自定义异常时也能回滚事务,有两种处理方式:

#1. 定义该自定义异常类时使用@ApplicationException(rollback=true)

#2. 程序中显式捕获该异常,然后调用ctx.setRollback(true);代码来控制事务回滚。

posted on 2015-01-26 10:39  逝者如斯(乎)  阅读(350)  评论(0编辑  收藏  举报