JBoss平台下JTA与JMS实验软件架构8
1 JTA 简介: Java Transaction API,JTA Transaction 是指由J2EE Transaction manager 去管理的
事务。通过调用UserTransaction 接口的begin,commit 和rollback 方法来完成事务范围
的界定,提交和回滚。实现同一事务对应多个的数据库。
2 JBoss 简介: JBoss 是一个基于J2EE 的开放源代码的应用服务器,JBoss 是一个管理EJB
的容器和服务器,支持EJB 1.1、EJB 2.0 和EJB3.0 的规范。但JBoss 核心服务不包
括支持servlet/JSP 的WEB 容器,一般与Tomcat 或Jetty 绑定使用。
3 分布式事务: “分布式事务”是指在多个进程中运行或者涉及到多个物理数据库连接的
事务。
椭圆指示在不同服务器上执行的工作,箭头指示远程方法调用
4 两阶段提交协议: 分布式事务使用两阶段提交协议使不同进程或者不同数据库服务器
执行的相关工作同步。该协议保证所有进程成功完成工作或根本不执行工作。对数据的
修改须共同提交或共同回滚。两阶段提交协议包含两个阶段:准备阶段和解决阶段。
5 准备阶段:协调者将向事务中的每个进程发送一条信息,要求每个进程准备提交。
当某进程准备时,它保证可以提交事务并为自己的工作生成一条永久记录。在保证
可以提交之后,它不能再单方面决定回滚事务。如果该进程不能准备(也就是说,
如果它不能保证自己可以提交事务),那么它必须回滚事务。
6 解决阶段:协调者记录响应。如果所有参与者都准备提交,则提交事务;否则回滚
事务。无论哪种情况,协调员将会把结果通知所有参与者。如果结果为提交,参与
者须确认它们已经提交。
只要你在事务中调用了多个数据库连接,就需要JTA。只要你在事务中调用了多个数据
库服务器,就需要两阶段提交.
7 应用程序中使用JTA: 分七个步骤
1) 建立事务:实现过程的第一步是建立UserTransaction 类的一个实例,可以在JNDI
中查找这个类。例:
Context ctx= GetInitialContext();
UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction");
2) 启动事务:只要调用UserTransaction 对象的begin 方法即可。例:
tx.begin();
3) 定位数据源:定位事务中所涉及到的数据源。例:
javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup(“datasource-name”);
4) 建立数据库连接
例: java.sql.Connection myConn = ds.getConnection();
5) 执行资源操作:执行数据库的相关操作:如插入,查询,删除等。
6) 关闭连接
例: stmt.close(); myConn.close();
7) 完成事务
例: try{ tx.commit(); stmt.close(); }
catch( Exception txe ){
try{ tx.rollback(); }
catch(javax.transaction.SystemException se){}
}finally{...}
8 JMS 简介: Java Message Service,JMS(Java Message Service)是访问企业消息系统的标准
API,它便于消息系统中的Java 应用程序进行消息交换,并且通过提供标准的产生、发
送、接收消息的接口简化企业应用的开发。
下面介绍一下JMS 的组成:
1) JMS 客户端:发送和接收消息的客户端Java 程序;
2) 消息:JMS 应用在不同客户端传递的消息;
3) JMS 提供者:实现JMS 的消息系统,并且提供管理和控制功能;
4) 管理对象:管理对象是预定义的JMS 对象,客户端使用这些预定义的对象进行通
信,例如后面介绍的连接工厂。
JMS 的简洁定义:
1) 连接工厂(ConnectionFactory):客户端用来创建连接的管理对象。
2) 连接(Connection):代表一个与JMS 提供者的活动连接。
3) 目的(Destination):标识消息接收方式。
4) 会话(Session):接收和发送消息的会话线程。
5) 消息生产者(MessageProducer):会话使用它把消息发送到目的地。
6) 消息消费者(MessageConsumer):会话使用它从目的地接收消息生产者发送的消息。
JMS 的基本功能: JMS 既支持点对点(PTP),又支持发布/订阅(publish/subscribe)的消息模型。
9 点对点(PTP): queue 是另外一种方式,仅仅允许一个消息传送给一个客户。一个发
送者将消息放在消息队列中,接受者从队列中抽取并得到消息,消息就会在队列中
消失。第一个接受者抽取并得到消息后,其他人就不能再得到它。
11 应用程序中使用JMS: 分为一下几个步骤
1) 得到一个JNDI 初始化上下文;
2) 根据上下文来查找一个连接工厂(两种连接工厂);
3) 从连接工厂得到一个连接(两种连接);
4) 通过连接来建立一个会话(Session);
5) 查找目的地(Topic/ Queue);
6) 根据会话以及目的地来建立消息制造(TopicPublisher/QueueSender)和消费者
(TopicSubscriber/QueueReceiver)。
JMS API 基本对象:
Queue topic
连接工厂 QueueConnectionFactroy Topic ConnectionFactroy
连接 QueueConnection TopicConnectionFactroy
会话 QueueSession TopicSession
目的地 Queue Topic
12 连接工厂:连接工厂由服务器管理员创建,并在启动时被绑定到JNDI 中。JMS 客
户端使用JNDI 查找连接工厂,然后使用连接工厂建立JMS 连接。
例: QueueConnectionFactory qConFactory =
(QueueConnectionFactory)ctx.lookup("ConnectionFactory");
13 连接:JMS 连接代表JMS 客户端和JMS 服务器之间的活动连接。JMS 客户湍端创建
JMS 连接方法是调用ConnectionFactory 的createQueueConnection 或
createTopicConnection 方法。
例: QueueConnection qCon = qConFactory.createQueueConnection();
14 会话:JMS 会话代表客户端与JMS Server 的交谈状态,可以从JMS 连接中创建会话。
例: QueueSession session = qCon.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
15 目的地:JMS 目的地是生产者和消费者的实际消息传递资源。有两种类型:Queue
和Topic。服务器管理员配置带有指定JNDI 的目的地,然后,JMS 客户端执行JNDI
查找来定位JMS 目的地,并创建相应的生产者和消费者。
例: Queue messageQueue = (Queue) ctx.lookup("MessageQueue");
消息发送与接收:
16 生产者:在JMS 中用会话来创建消息的发送对象和消息文本对象。
例: QueueSender sender = session.createSender(messageQueue);
TextMessage msg = session.createTextMessage();
msg.setText("hello"); sender.send(msg);
1>消费者:消息消费者可以从会话中创建一个接受对象。
例: QueueReceiver receiver = session.createReceiver(messageQueue);
同步与异步接收:
2>同步消费者:同步消费者使用receive()方法向JMS 服务器请求这个目的地的下一条
消息,receive()会阻塞,直到这个目的上有一条可用的消息为止。
例: TextMessage msg = (TextMessage) receiver.receive();
3>异步消费者:异步消费者必须使用接受对象的setMessageListener 方法,并传递一
个实现了javax.jms.MessageListener 接口的对象。最后,由QueueConnection 的start
方法开消息监听。
例: receiver.setMessageListener(this); qCon.start();
<三>实验步骤:
1) 安装JBoss: 到JBoss 官方网站http://www.jboss.org/jbossas/downloads/下载JBoss
压缩包,下载jboss-4.0.2,解压后的目录就是JBoss 的安装目录,注意安装目录不
要包含有中文。然后安装JDK 并配置环境变量,配置过程详见前面的实验。本次实
验连接的数据库是MySQL,检查机子上有没有安装MySQL 程序,如果没有则要安
装,记住设定的密码。
2) 创建数据库:
其中的密码我们设置为mysql数据库的密码:<password>123</password>
修改%JBOSS-HOME%/server/default/conf 下的standardjbosscmp-jdbc.xml 文件,找到
<datasource>,将该行改为<datasource>MySqlDs</datasource>,(与jndi-name 对应)。
4) 下面提供两种获取JBoss 上下文的方法,不过在该实验中,我们采用第二种方法。
a) 配置JNDI 的一个方法是通过属性文件\server\minimal\conf \jndi.properties。在
这个文件中使用正确的值,并且把它所在的路径包含到classpath 中,它比较
容易获得正确初始化上下文。
jndi.properties 文件的内容如下:
java.naming.factory.initial=org.jboss.naming.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
把该文件放置的路径成为你的classpath 的一部分。如果你使用这种方法,在
初始化上下文时,代码比较简单: Context context = new IntialContext(); 。当程
序是通过外部访问JBoss 才需要jndi.properties 文件,如果程序在JBoss 服务器
中运行,如:Servlet 或jsp,则只要new InitialContext()。
b) 在某些情景下,可能需要手工配置JNDI;例如当运行的类文件中环境已经配
置了一个初始化上下文,但不是你想用的上下文时,需要手工来配置一个上下
文:
String url = "jnp://localhost:1099";
Properties p = new Properties();
p.setProperty("java.naming.factory.initial","org.jboss.naming.NamingContextFactory");
p.setProperty("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
p.setProperty("java.naming.provider.url",url);
ctx = new InitialContext(p);
5) JBoss 与JTA:
a) 获取JTA 对象UserTransaction:
UserTransaction tx = null;
tx=(javax.transaction.UserTransaction)ctx.lookup("UserTransaction");
b) 开始事务:tx.begin();
c) 提交事务:tx.commit();
d) 事务回滚:tx.rollback();
6) 检查JTA 配置是否成功:
代码文件在JTA 文件夹中,根据自己机子的配置路径修改setEnv.cmd 文件中信息:
jboss_home:E:\jboss-4.0.2\
java_home:C:\Program Files\Java\jdk1.6.0_05
运行JBoss:JBoss 目录下bin\run.bat。若出现错可能是配置有问题。
编译:执行compile.cmd 文件,生成jtatest.class 文件。
执行:点击runJTAtest.cmd,将会看到执行的结果。
7) JBoss 部署JTA 的servlet:
为了让JBoss 的JTA 正常运行,在servlet 中运行JTA,让JTA 在JBoss 服务器的
虚拟机上运行。代码文件在JTA-Servlet 文件夹中,按以下步骤在JBoss 部署
Servlet。
编译环境配置:将JBoss 中的
%JBOSS-HOME%/server/default/lib/javax.servlet.jar 文件拷贝到jdk 安装目录
下的jre\lib\ext 目录下(注: 是JDK 下的JRE),配置好setEnv.cmd。
编译:执行compile.cmd 文件,然后把生成的JTAservlet.class 文件复制到
WEB-INF\classes\com\servlet 下。
打包:执行packet.cmd。将生成两个文件:JTAServlet.ear 和JTAservlet.war。
部署:把上步打包的的JTAServlet.ear 放到:
%JBOSS_HOME%\server\default\deploy 中。
运行:在IE 中输入:
http://localhost:8080/JTAtest/servlet/JTAservlet
8) 事务回滚: 当提取的现金的额度大于现有的额度,则会撤销提取的操作,将事务进
行回滚到操作之前的状态。打开MySQL 命令行,输入命令: use lab9; select * from
jbossaccounts; 将查看到jbossaccounts 中的信息。代码文件在JTA-RollBack
文件夹中,配置好setEnv.cmd 并编译,执行runJTAsql.cmd,如果回滚成功,
jbossaccounts 表中的信息不变。
9) JBoss 下配置JMS: JMS 是Java API,允许应用程序来建立、接收和读取消息。程
序依靠这些API,在运行时需要一个JMS 实现接口,来提供管理和控制,这被称为
JMS provider。JBoss 中的JMS Provider 叫做JbossMQ ,JbossMQ 是通过xml 文
件jbossmq-service.xml 进行配置的,该文件放在在server\default\deploy\jms
下。
最基本的三件事情:
a) 增加目的地
b) 配置用户
c) 获得可用连接工厂的名字。
本实验后两步先不考虑。
10) 增加新的目的地: 有关JMS 的所有目的地配置在
%JBOSS_HOME%/server/default/deploy/jms/jbossmq-destinations-service.xml
添加目的地:例:添加一个名为MessageTopic 的Topic 的目的地
<mbean code="org.jboss.mq.server.jmx.Topic"
name="jboss.mq.destination:service=Topic,name=MessageTopic">
<depends optional-attribute-name="DestinationManager">
jboss.mq:service=DestinationManager</depends></mbean>
客户端程序编译和运行是需要必要的包,这些包都放在%JBOSS_HOME%/client 目录
中,所以,你要把程序中用到的包添加到classpath 中,为了方便,可以把它写成
一个.cmd 文件,请看setEnv.cmd。其中的JAVA_HOME,JBOSS_HOME,要根据自己
的机子情况做相应修改。
(topic)生产者消费者运行结果:
生产者:
JBoss平台下JTA与JMS实验,jta是关于事务处理的。Jta主要用通过转账的值是否大于现存的值,如果没有,则转账不成功,且数据库的值恢复到原来的正确的值。 jms只是关于点对点消息传递(queue)与点对多(或多对多)的消息传递(topic)。其中目的地对象必须在特定的jms服务器之中建立,jms服务器管理员创建带有指定jndi名称的目的地,然后jms客户端执行jndi查找来定位jms目的地,并创建相应的消费者或者生产者,一个jms应用程序可以使用多个目的地对象,目的地对象可以分为queue,与topic两种,目的地对象定义在点对点消息传递域,目的地称为queue,定义在发布/订阅消息传递域,目的地对象称为topic,目的地对象是持久化对象。(个人觉得队列形式的消息只能一个人享用,二发布/订阅模型的一条消息只有所有订阅该消息的人都阅读完才销毁该消息。)