EJB3.0学习笔记

来源:互联网 发布:手机惠普打印机软件 编辑:程序博客网 时间:2024/04/28 22:06

3.2 EJB实例分析

该实例是运行在JBOSS5.1与SQLServer2005下。

(1)  会话BEAN

对于会话Bean的开发,相对简单如图:

图3.4 会话Bean接口声明

声明接口即与使用此EJB的用户签定了契约。用户可以使用接口提供的功能。当然要为接口实现此功能如图:

图3.5 会话Bean服务实现类

对于接口服务的实现,EJB3中使用了更为方便的标签方式,声明这个Bean并为其指定接口。完成之后,即可以向外提供服务,需要组织成构件,如图:

 

图3.6 jar文件

当这个jar文件部署到服务器中时,服务器解析此为一个EJB的实体Bean,并向外提供服务。

图3.7 调用EJB服务代码

 

图3.8 调用结果显示

(2)  实体BEAN

由于实体BEAN的开发就要涉及与数据库的关联,所以要配置数据源

对于JBOSS数据源的配置做简单的介绍。

对于JBOSS5.1数据源的配置,在目录docs/example/jca中已经包含了相关的数据源配置的xml例子文件,如图:

图3.9 数据源配置xml文档

首先复制一份文件,并修改

<?xml version="1.0"encoding="UTF-8"?><datasources> <local-tx-datasource>   <jndi-name>MSSQLDS</jndi-name>//这是设置jndi名称以供在程序能够找到这个数据源   <connection-url>jdbc:sqlserver://localhost:1433;DatabaseName=MBOOK</connection-url>   <driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>   <user-name>sa</user-name>   <password>123456</password>     <metadata>        <type-mapping>MS SQLSERVER2005</type-mapping>     </metadata> </local-tx-datasource></datasources>


 

 

修改好这个文件,同时需要把SQLServer2005所用的jdbc驱动包拷贝到jboss-5.1.0.GA\server\default\lib目录下,如图:

图3.10 数据驱动jar包

然后将文件移动到目录jboss-5.1.0.GA\server\default\deploy发布。如果此时你的jboss已经是启动状态,则会看到控制台打印:

图3.11 数据源加载成功

表示数据源加载成功。

接下来可以写你的EJB应用:

需要注意的是在实体Bean中,(注意实体bean中,get方法才有ejb的标签。另要确保实体bean有一个默认的的构造函数)需要包含一个persistence.xml文件,此文件在导出jar包的时候也要包含。此文件可以为此EJB对象指定数据源。即上面已经配置好的并加载进JBOSS中的。

<persistencexmlns="http://java.sun.com/xml/ns/persistence"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"    version="1.0">     <!--持久化单元 transaction-type事物的类型。一个是全局事物JTA,一个是本地事物 -->    <persistence-unitname="sql"transaction-type="JTA">       <jta-data-source>java:MSSQLDS</jta-data-source>       <!--当数据源发布到jboss的时候,他的jndi名称默认是在java:的命名空间里 , 需要加上,jndi默认是在全局上找的 -->       <properties>//注意如如果下面方言不配置,有时是会报错的。           <propertyname="hibernate.dialect"value="org.hibernate.dialect.SQLServerDialect"/>           <propertyname="hibernate.show_sql"value="true"/>           <propertyname="hibernate.format_sql"value="true"/>           <propertyname="hibernate.jdbc.fetch_size"value="50"/>       </properties>    </persistence-unit></persistence>


 

 

 

jndi.properties文件在测试时和应用EJB时是必不可少的。

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

java.naming.provider.url=localhost:1099

 

发布到jboss-5.1.0.GA-jdk6\jboss-5.1.0.GA\server\default\deploy目录下:

图3.12 发布EJB

如上图,已经成功发布了EntityBeanTest的EJB,该EJB是以jar文件形式存在的。并且还指出了beanName为PersonServiceBean,以及接口名IPersonService.

测试如下:

publicclass PersonServiceTest {     privatestatic IPersonServicepersonService;     @BeforeClass         publicstaticvoid setUpBeforeClass()throws Exception {              try {                 InitialContextic =new InitialContext( );                 personService = (IPersonService)ic.lookup("PersonServiceBean/remote");             } catch (Exception e){                e.printStackTrace();             }          }      @Test    publicvoid testSave() {       personService.save(newPerson("sunquan"));      }}


 

执行成功,由于在persistence.xml中showSql为true,控制台显示了相应的sql语句。

图3.13 SQL语句

查看数据库:

图3.14 数据添加成功

收到对应结果。

1.  有几点需要注意,在数据库的设计过程中,id必须设为主键,且自增长。

2.  导入jboss/client的所有jar包。由于持久化操作,所以需要hibernate.jar包。

 

这样对于一个实体的bean,对应数据库中的一张表,并且包括对于数据的相应操作,就都包含在这个EJB对象当中。

(3)  消息驱动BEAN

消息驱动BEAN的特性有如异步调用,无状态特性,以及无本地远程接口等。

对于一个消息驱动BEAN,即当客户端发送一条消息时,该BEAN能够自动响应这条消息。能过客户端的消息来驱动该BEAN的调用、执行。

那么首先要存在这样一个所谓消息BEAN,并且他能够监听特定的消息。

packagecn.sunquan.MessageBean;importjavax.ejb.ActivationConfigProperty;importjavax.ejb.EJBException;importjavax.ejb.MessageDriven;importjavax.ejb.MessageDrivenBean;importjavax.ejb.MessageDrivenContext;importjavax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;importjavax.jms.TextMessage;@MessageDriven(mappedName="MyMessageDrivenBean",activationConfig = {              @ActivationConfigProperty(propertyName ="destinationType", propertyValue ="javax.jms.Queue"),       @ActivationConfigProperty(propertyName ="destination", propertyValue ="queue/itmQueue")})//关于上述标签的解释:destination指明要去监听容器通道的名字,destinationType指//明要去监听容器通道的类型。mappedName非必须的。publicclassMyMessageDrivenBeanimplements MessageDrivenBean, MessageListener {    privatestaticfinallongserialVersionUID = 1L;    publicMyMessageDrivenBean() {       //TODO Auto-generated constructor stub    }    @Override    publicvoid onMessage(Messagemessage) {       TextMessagemsg = (TextMessage) message;       try {           System.out.println(msg.getText());       } catch (JMSException e) {           e.printStackTrace();       }    }    @Override    publicvoid ejbRemove()throws EJBException {    }    @Override    publicvoidsetMessageDrivenContext(MessageDrivenContext arg0)           throws EJBException {       }}


 

 

下面这个xml文件就是声明上述那个通道,打在jar包和单独发布到deploy目录下效果一样。

<?xmlversion="1.0"encoding="UTF-8"?> <server>   <mbeancode="org.jboss.mq.server.jmx.Queue"          name="jboss.mq.destination:server=Queue,name=itmQueue">             <attributename="JNDIName">queue/itmQueue</attribute>             <dependsoptional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>   </mbean>  <!--  <mbeancode="org.jboss.mq.server.jmx.Topic"         name="jboss.mq.destination:service=Topic,name=itmTopic">       <attributename="JNDIName">topic/itmTopic</attribute>     <dependsoptional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>     </mbean>     --> </server>


 

 

 

测试发现在bean打成jar包后,如果不包含上述这个xml的文件(xxx-service.xml)时,这个消息驱动bean是bound不成功的。为什么呢?

图3.15 绑定不成功

既然JBOSS已经发现了一个叫做itemQueue类型的消息,服务器此时只能从bean中的标签中发现itemQueue,至此服务器已经知道有一个bean,

他是处理itemQueue类型的。当一个itemQueue消息发送过来的时候,服务器应该是可以把这条消息交给指定bean处理的,或者是这个bean一直在等待,类似监听这类消息,一旦有就处理。(仅是猜测)

那么EJB消息驱动Bean是哪种处理方法的呢?

很明显,由于异步的需要,是采用的第二种,BEAN一直在监听。那么JBOSS就要为这个BEAN开辟一条通道,让BEAN在这条通道上监听,发送对应类型的消息时,也发送到这个通道上。那么我们就需要为JBOSS指定这个通道,然后把BEAN绑定到这条通道上。

(同时联想到bean中的一个属性名是destination,目的地,bean是消息处理的终点,怎么还有目的地,哈哈,此处的意思是去容器的一个目的通道上监听。)

而上面我们只声明了BEAN,JBOSS中确不存在这条通道,而你的bean又要去这里监听,那么JBOSS服务器会显示指定的通道没有绑定。

 

所以有理由相信,所以要通过上面xml文件使用容器创建一个通道(该文件可以打包在jar文件中,也可以只直接以xml文件的方式发布在deploy目录下,其效果是一样的):

 

 

图3.16 绑定成功

 

接下来就是处理发送消息:

package cn.sunquan.send;import java.util.Properties;import javax.jms.Queue;importjavax.jms.QueueConnection;import javax.jms.QueueConnectionFactory;import javax.jms.QueueSession;import javax.jms.TextMessage;import javax.naming.InitialContext;publicclass QueueSender {    publicstaticvoid main(String[]args){        try {          Properties props = new Properties();           props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");           props.setProperty("java.naming.provider.url","localhost:1099");           props.setProperty("java.naming.factory.url.pkgs","org.jboss.naming");           InitialContext ctx = new InitialContext(props);                     //查找 QUeue类型的连接工厂。             QueueConnectionFactory factory = (QueueConnectionFactory)ctx                    .lookup("ConnectionFactory");                     QueueConnection conn=factory.createQueueConnection();                     //创建一个到该地址的会话,第二个参数:消息的确认模式,这里用自动的确认模式。             QueueSession session = conn.createQueueSession(false,                      QueueSession.AUTO_ACKNOWLEDGE);                  Queue queue = (Queue) ctx              .lookup("queue/itmQueue");                          TextMessage msg =session.createTextMessage("您好,这是我的第一个消息驱动Bean");           javax.jms.QueueSender sender=session.createSender(queue);           sender.send(msg);           session.close();              conn.close();          } catch (Exception e) {             e.printStackTrace();         }      }  }


 

可以看到lookup时是找的queue/itmQueue

图3.17 绑定成功

 

即在bean中指定的destination.

图3.18 显示结果

 

 

(注:上面的xxx-service.xml既然可以放在jar包中,那么实体bean中的dataSource.xml声明是否也可以放在实体bean的jar包中……)

 

 

下载:

HelloWorldEJB

EntityBeanTest

MessageBeanTest

原创粉丝点击