Enterprice
JavaBeans
是一个用于分布式业务应用的标准服务端组件模型。采用
Enterprice
JavaBeans
架构
编写的应用是可伸缩的、事务性的、多用户安全的。
采用
ejb
编写的这些应用,可以部署在任何支持
Enterprice
JavaBeans
规范的服务器平台,如
jboss
、
weblogic
等。
EJB
实际上是用于编写业务层代码。
我们知道一个基于
MVC
结构的应用应包含显示层、控制层和业务层
,
假设我们采用
ejb
开发基于
MVC
结构的应用
,
那么
ejb
就是用于开发应用的业务层
.
EJB最大的特点是分布式,EJBs都是业务层的东西,对于多个显示层可以做到业务层完全不用改变。我们写的EJBs发布到EJB容器比如JBOSS中,客户端(普通
Java
应用或者JavaWeb应用)通过JNDI找到你的EJB,这中间通过socket通信,为了降低这种消耗,可以定义本地的EJB,但是这个EJB必须和你的客户端在同一个JVM中,即一个JBoss中,比如你的JavaWeb发布到这个JBoss中。
EJB
为我们提供了很多在企业开发中需要使用到的服务
,
如事务管理
/
安全
/
持久化
/
分布式等
,
因为这些服务由容器提供
,
无需我们自行开发
,
这样大大减少了我们的开发工作量
.
另外
EJB
提供了强制式分层解耦设计方法
EJB3.0运行环境
EJB3.0
应用需要运行在
JDK1.5
以上版本。
进入
http://java.sun.com/javase/downloads/index_jdk5.jsp
下载
JDK
。在页面中找到
JDK5.0 Update 16
(版本在不断更新中,有可能大于
16
),点击右边的
Download
。
按照安装向导提示安装,安装路径选择
C:\Java\jdk1.5.0_16
。
Jdk
安装完后,接着问你是否安装
jre
,也一起安装上。
右键点击“我的电脑”
->
“属性”
->
“高级”
->
“环境变量”,在“系统变量”里添加
JAVA_HOME
变量,值为
JDK
的安装路径,如:
C:\Java\jdk1.5.0_16
。
在“系统变量”里再添加
CLASSPATH
变量,值为:
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
在系统变量栏找到变量名为
Path
的选项,点“编辑”在变量值的末尾添加
;%JAVA_HOME%\bin;
EJB3.0
应用需要运行在
EJB
容器里,下面是一些
JavaEE
应用服务器,
JavaEE
应用服务器包含
Web
容器和
EJB
容器。
l
Jboss
(
4.2.x
以上版本)
是一个成熟的开源的准
JavaEE
应用服务器,在开源
JavaEE
应用服务器中所占市场份额第一。如果你打算选用开源的
JavaEE
应用服务器,那么
jboss
是最值得选择的。
l
Glassfish
是一个开源的
JavaEE
应用服务器,对
JavaEE
规范的支持非常好,其运行性能比较高。因为发展时间相对较短,市场占有率比较低。另外,它能否提供稳定的运行性能,还有待时间的考验。
l
Weblogic
(
10
以上版本)
是商业市场占有率第一的商业
JavaEE
应用服务器,它具有出色的稳定性,并提供了人性化的管理界面,还有企业需要使用到的众多功能。
l
Sun ApplicationServer
(
9.0
以上版本)
商业
JavaEE
应用服务器,如果你打算选用商业应用服务器运行
ejb3
,这个是不错的选择。
l
Oracle ApplicationServer
(
10g
以上版本)
商业
JavaEE
应用服务器,如果你的
数据库
是
Oracle
,要想兼容性更好,这个是不错的选择。
l
apusic
应用服务器
这是国内的商业
JavaEE
应用服务器,主要在政府中占有一定的市场份额。但是其向开发人员提供的文档实在太少了。
注意:
Tomcat
目前只是
Web
容器,它不能运行
EJB
应用。
进入http://labs.jboss.com/jbossas/downloads/下载页面,选择jboss4.2.3.GA下载(大小为95MB),如果你安装的jdk是1.5版本,请选择jboss-4.2.3.GA.zip文件下载。如果你安装的jdk是1.6版本,请选择jboss-4.2.3.GA-jdk6.zip文件下载。下载后直接解压缩文件即可完成安装,为了避免应用出现莫名的错误,解压缩的路径最好不要带有空格和中文,如“Program Files”。
进入
jboss
的
bin
目录,找到
启动脚本
run.bat
。双击
run.bat
即可启动
jboss
,此时启动的配置项为
default
。
如果启动出错,请检查下列情况
:
1.
端口是否被占用,如:
8080
、
1099
2
是否为
JDK
设置的
JAVA_HOME
和
ClassPath
系统变量,如果没有,请按照前面视频介绍的方法设置。
3.
检查
jboss
所用的
jdk
是否
1.5
以上版本,这些信息可以在
jboss
的控制台观察到。
4.
如果启动时出现这样的错误:“
findstr
不是内部或外部命令,也不是可运行的程序或批处理文件”。那么应该在系统变量
Path
中追加“
%SystemRoot%\system32;%SystemRoot%;
”
。
最后的办法是重装机器上的
JDK
,祝你好运。
l
因为在后面的学习中,我们需要使用到系统变量
JBOSS_HOME
,它指向
jboss
的安装路径。所以
安装完后
我们需要添加该变量,方法是:
右键点击“我的电脑”
->
“
属性”
->
“
高级”
->
“
环境变量”,
在“系统变量”里添加
JBOSS_HOME
变量,值为
Jboss
的安装路径,如:
D:\JavaEEServer\jboss
。
l
为了方便输入
jboss
的命令,我们把
jboss
的
bin
目录添加到系统路径里。
在系统变量一栏找到变量名为
Path
的选项,点“编辑”在变量值的末尾添加:
;%JBOSS_HOME%\bin;
•
开发
EJB
依赖的
jar
文件
可以在
jboss
安装路径的
client
目录下找到
,
通常会把
client
目录下的所有
jar
文件添加到项目的类路径下
.
EJB
中的三种
bean
1.
会话
bean(session bean)
负责与客户端交互
,
是编写业务逻辑的地方
,
在会话
bean
中可以通过
jdbc
直接操作数据库
,
但大多数情况下都是通过实体
bean
来完成对数据库的操作
.
2.
实体
bean(entity bean)
它实际上属于
java
持久化规范
(
简称
JPA)
里的技术
,JPA
的出现主要是为了简化现有的持久化开发工作和整合
ORM
技术,结束现在
hibernate
、
TopLink
等
ORM
框架各自为营的局面。
3.
消息驱动
bean(message-driven bean)
它是专门用于异步处理
java
消息的组件
.
具有处理大量并发消息的能力
.
两种会话bean
•
无状态会话
bean
平常
,
我们使用最多的是无状态
bean,
因为它的
bean
实例可供多个用户使用
,
所以它的性能比有状态
bean
高
.
正因为一个
bean
实例被多个用户使用
.
那么
,
前一个用户设置的值有可能被后一个用户所修改
,
所以它无法正确保存某个用户设置的值
,
因此是无状态的
.无状态
bean
使用
实例池
技术管理
bean
•
有状态会话
bean
有状态
bean
平常使用的并不多
,
因为它的一个
bean
实例只供一个用户使用
,
所以性能开销比较大
,
正因为它的实例只被一个用户使用
,
用户为它设置的值是不会被其他用户修改
,
所以可以正确保存用户设置的值
,
因此是有状态的
.
有
状态
bean
使用
激活
(activation)
管理
bean
每个用户都有自己的
Bean
实例,相当于有多少个用户就有多少个
Bean
实例为之服务。如果不采取任何机制,这样必然会导致服务器资源严重消耗,最后落个
down
机罢工。为了解决这个问题,
EJB
引入了激活机制。该机制实现的原理是这样的,在
EJB
服务器需要节省资源时,就从内存中收回
bean
实例,将其所保持的会话状态序列化到硬盘中,并且释放其所占有的内存。若此时客户端对
EJB
再次发起请求,
EJB
容器会重新实例化一个
Bean
实例,并从硬盘中将之前的状态恢复。
客户端编程
public static void main(String[]
args
) {
Properties props =
new Properties();
props.setProperty
(”
java.naming.factory.initial
“,”
org.jnp.interfaces.NamingContextFactory
“);
props.setProperty
(”
java.naming.provider.url
”
,”
localhost:1099
“);
try {
InitialContext
ctx
=
new
InitialContext
(props);
HelloWorld
helloworld
= (
HelloWorld
)
ctx.lookup
(”
HelloWorldBean
/remote
“);
System.
out.println
(
helloworld.sayHello
(”
佛山
“));
}
catch (
NamingException
e) {
System.
out.println
(
e.getMessage
());
}
}
设置JNDI访问环境信息
在进行
JNDI
查找前,我们必须设置应用服务器的上下文信息,主要是设置
JNDI
驱动的类名(
java.naming.factory.initial
)和命名服务提供者的
URL
(
java.naming.provider.url
) 。
l
java.naming.factory.initial
或
Context.INITIAL_CONTEXT_FACTORY
:环境属性名,用于指定
InitialContext
工厂(作者称它为
JNDI
驱动更容易理解),它类似于
JDBC
指定数据库驱动类。
因为本例子连接的是
JbossNS
(命名服务的实现者),所以使用
Jboss
提供的驱动类:
org.jnp.interfaces.NamingContextFactory
l
java.naming.provider.url
或
Context.PROVIDER_URL
:环境属性名,包含提供命名服务的主机地址和端口号。它类似于
JDBC
指定数据库的连接
URL
。连接到
JbossNS
的
URL
格式为:
jnp://host:port
,该
URL
的“
jnp:
”部分是指使用的协议,
JBoss
使用的是基于
Socket/RMI
的协议。
host
为主机的地址,
port
为
JNDI
服务的端口。除了
host
之外,其他部分都是可以不写的。
l
下面是数据库访问例子
:
Class.forName(“org.gjt.mm.
MySQL
.Driver”).newInstance();
Properties props = new Properties();
props.put(“user”,”root”);
props.put(“password”,”123456″);
Connection conn =
DriverManager.getConnection(“jdbc:mysql://
localhost:3306
/itcast”,
props
);
如同数据库一样,根据访问命名服务器的不同,为上下文设置的驱动类和
URL
也是不同的,如下面是访问
Sun
应用服务器的上下文信息:
Properties props =
new
Properties();
props.setProperty
(”
java.naming.factory.initial
“, ”
com.sun.enterprise.naming.SerialInitContextFactory
“);
props.setProperty
(”
java.naming.provider.url
“, ”
localhost:3700
“);
InitialContext
=
new
InitialContext
(props);
HelloWorld
helloworld
= (
HelloWorld
)
ctx.lookup
(“com.foshanshop.ejb3.HelloWorld”);
如果客户端运行在应用服务器内,我们不需要为
InitialContext
设置应用服务器的上下文信息,也不建议设置。因为应用服务器启动时会把
JNDI
驱动类等上下文信息添加进系统属性,创建
InitialContext
对象时如果没有指定
Properties
参数,
InitialContext
内部会调用
System.getProperty
()
方法从系统属性里获取必要的上下文信息。对本例子而言,你可以省略传入
props
参数,之所以给
InitialContext
设置参数,目的是引出相关知识点,便于教学。在实际应用中,如果给
InitialContext
设置了参数,反而会带来不可移植的问题。
注:创建
InitialContext
对象时如果没有指定
Properties
参数,
InitialContext
还会在
classpath
下寻找
jndi.properties
文件,并从该文件中加载应用服务器的上下文信息。这样避免了硬编码为
InitialContext
设置
Properties
参数。
jndi.properties
的配置如下:
java.naming.factory.initial
=
org.jnp.interfaces.NamingContextFactory
java.naming.provider.url
=localhost:1099
java.naming.factory.url.pkgs
=
org.jboss.naming:org.jnp.interfaces
当
EJB
发布到
Jboss
时,如果我们没有为它指定全局
JNDI
名称或修改过其默认
EJB
名称,
Jboss
就会按照默认的命名规则为
EJB
生成全局
JNDI
名称,默认的命名规则如下:
如果把
EJB
作为模块打包进后缀为
*
.ear
的
Java EE
企业应用文件,默认的全局
JNDI
名称是
l
本地接口:
EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local
l
远程接口:
EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote
EAR-FILE-BASE-NAME
为
ear
文件的名称,
EJB-CLASS-NAME
为
EJB
的非限定类名。
例:把
HelloWorld
应用作为
EJB
模块打包进名为
HelloWorld.ear
的企业应用文件,它的远程接口的
JNDI
名称是:
HelloWorld
/
HelloWorldBean
/remote
如果把
EJB
应用打包成后缀为
*
.jar
的模块文件,默认的全局
JNDI
名称是
l
本地接口:
EJB-CLASS-NAME/local
l
远程接口:
EJB-CLASS-NAME/remote
例:把
HelloWorld
应用打包成
HelloWorld.jar
文件,它的远程接口的
JNDI
名称是:
HelloWorldBean
/remote
使用注释改变会话bean的JNDI名
如果我们没有指定
EJB
的
JNDI
名称,当
EJB
发布到应用服务器时,应用服务器会按默认规则为
EJB
生成全局
JNDI
名称。当我们需要自定义
JNDI
名称时,可以这样做
如果
EJB
在
Jboss
中使用,可以使用
Jboss
提供的
@
LocalBinding
和
@
RemoteBinding
注释,
@
LocalBinding
注释指定
Session Bean
的
Local
接口的
JNDI
名称,
@
RemoteBinding
注释指定
Session Bean
的
Remote
接口的
JNDI
名称,如下:
@Stateless
@Remote ({
Operation.class
})
@
RemoteBinding
(
jndiBinding
=”
foshanshop
/
RemoteOperation
“)
@Local ({
LocalOperation.class
})
@
LocalBinding
(
jndiBinding
=”
foshanshop
/
LocalOperation
“)
public class
OperationBean
implements Operation,
LocalOperation
{
}
使用
xml
部署描述文件
改变
SessionBean
的
JNDI
名称
由于
JNDI
名称与厂商有关,如果使用注释定义
JNDI
名称会带来移植问题,因此建议使用
ejb-jar.xml
部署描述文件进行定义,该文件必须放置在
jar
的
META-INF
目录下
<?xml version=”1.0″encoding=”UTF-8″?>
<
ejb
-jar
xmlns
=
http://java.sun.com/xml/ns/javaee
xmlns:xsi
=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation
=”http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd” version=”3.0″>
<enterprise-beans>
<session>
<
ejb
-name>
HelloWorldBean
</
ejb
-name>
<mapped-name>
HelloWorldBean
</mapped-name>
</session>
</enterprise-beans>
</
ejb
-jar>
ejb
-name
为
EJB
名称,
mapped-name
为
bean
的
JNDI
名称。目前
jboss
不支持在
ejb-jar.xml
通过
mapped-name
指定
JNDI
名称,但我们可以使用他专属的部署描述文件
jboss.xml
进行定义,如下:
<?xml version=”1.0″encoding=”UTF-8″ ?>
<!DOCTYPE
jboss
PUBLIC “-//
JBoss
//DTDJBOSS 4.2//EN“ “http://www.jboss.org/j2ee/dtd/jboss_4_2.dtd”>
<
jboss
><enterprise-beans> <session>
<
ejb
-name>
HelloWorldBean
</
ejb
-name>
<
jndi
-name>hello/remote</
jndi
-name>
</session></enterprise-beans></
jboss
>
本地接口的bean
@Local ({
HelloWorldLocal.class
})
EJB的调用机制
由于
EJB
的调用过程对开发者来说是透明的,以至于我们错误地认为:
lookup()
方法返回的对象就是
bean
实例。实际上,客户端与
Session bean
交互,它并不直接与
Bean
实例打交道,而是经由
bean
的远程或本地接口。当你调用远程或本地接口的方法时,接口使用的是存根(
stub
)对象。该存根实现了
session bean
的远程或本地接口。它负责将方法调用经过网络发送到远程
EJB
容器,或将请求路由到位于本地
JVM
内的
EJB
容器。存根是在部署期间使用
JDK
所带的
java.lang.reflect.Proxy
动态生成。利用RMI、远程代理实现远程调用。
第一步
:客户端调用远程接口的
SayHello
()
方法(实际上调用的是存根对象的
SayHello
()
方法,该存根实现了
HelloWorld
的远程接口)。
第二步
:方法调用经过
IIOPRuntime
被转换成
CORBA IIOP
消息发往应用服务器。
第三步
:应用服务器接收到请求消息后,交由骨架(
skeleton
)处理。骨架通过
IIOP Runtime
解析协议消息,并根据协议要求调用
bean
实例的
SayHello
()
方法。
第四步
:骨架(
skeleton
)将
SayHello
()
方法的返回值经过
IIOPRuntime
转换成
CORBA IIOP
应答消息发回客户端。
第五步:存根对象通过
IIOP Runtime
将
CORBAIIOP
应答消息解析成返回值。
EJB中的依赖注入
注入
ejb
:
@Stateless
@Remote (
Injection.
class
)
public
class
InjectionBean
implements
Injection {
@EJB(
beanName
=”
HelloBean
“)
LocalHello
helloworld
;
public
String
SayHello
() {
return
helloworld.SayHello
(”
注入者
“);
}
}
注入数据源
:
@Resource(
mappedName
= “java:/
DefaultMySqlDS
“)
DataSource
myDb
;
Connection
conn
= null;
try {
conn
=
myDb.getConnection
();
Statementstmt =
conn.createStatement
();
ResultSet
rs
=
stmt.executeQuery
(“SELECT
studentName
FROM student”);
if (
rs.next
())
str
=
rs.getString
(1);
rs.close
();
stmt.close
();
} catch (
SQLException
e) {
e.printStackTrace
();
}finally{
try {
if(null!=
conn
&& !
conn.isClosed
())
conn.close
();
} catch (
SQLException
e) {
e.printStackTrace
();
}
}
配置数据源
<?xml version=”1.0″encoding=”UTF-8″?>
<
datasources
>
<local-
tx
–
datasource
>
<
jndi
-name>
DefaultMySqlDS
</
jndi
-name>
<connection-
url
>
jdbc:mysql
://localhost:3306/
itcast?useUnicode
=
true&characterEncoding
=UTF-8</connection-
url
>
<driver-class>
org.gjt.mm.mysql.Driver
</driver-class>
<user-name>root</user-name>
<password>123456</password>
<min-pool-size>3</min-pool-size>
<max-pool-size>100</max-pool-size>
<!–
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE
<transaction-isolation>TRANSACTION_SERIALIZABLE</transaction-isolation>–>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>
mySQL
</type-mapping>
</metadata>
</local-
tx
–
datasource
>
</
datasources
>
实体Bean
它属于
java
持久化规范
(
简称
JPA)
里的技术,实体
bean
通过元数据在
javabean
和数据库表之间建立起映射关系,然后
Java
程序员就可以随心所欲的使用面向对象的编程思想来操纵数据库。
JPA
的出现主要是为了简化现有的持久化开发工作和整合
ORM
技术,目前实现的
JPA
规范的主流产品有
Hibernate
、
TopLink
和
OpenJPA
,
在
jboss
中采用了
Hibernate
作为其
持久化实现产品
。
添加
JPA
的配置文件
persistence.xml
根据
JPA
规范的要求:在实体
bean
应用中,我们需要在应用的类路径下的
META-INF
目录加入持久化配置文件
persistence.xml
<?xml version=”1.0″?>
<persistence
xmlns
=”http://java.sun.com/xml/ns/persistence”
xmlns:xsi
=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation
=”http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd”version=”1.0″>
</persistence>
<propertyname=”hibernate.hbm2ddl.auto” value=”create-drop”/>
<!–
显示最终执行的
SQL –>
<property name=”
hibernate.show_sql
” value=”true”/>
<!–
格式化显示的
SQL –>
<property name=”
hibernate.format_sql
” value=”true”/>
JMS(Java消息服务)
Java
消息服务(
Java
Message Service
,简称
JMS
)是用于访问企业消息系统的开发商中立的
API
。企业消息系统可以协助应用软件通过网络进行消息交互。
JMS
的编程过程很简单,概括为:应用程序
A
发送一条消息到消息服务器的某个目得地
(Destination)
,然后消息服务器把消息转发给应用程序
B
。因为应用程序
A
和应用程序
B
没有直接的代码关连,所以两者实现了解偶。如下图:
消息传递系统的中心就是消息。一条
Message
由三个部分组成:
头(
header
)
,
属性(
property
)和主体(
body
)。
消息有下面几种类型,他们都是派生自
Message
接口。
StreamMessage
:一种主体中包含
Java
基元值流的消息。其填充和读取均按顺序进行。
MapMessage
:一种主体中包含一组名
–
值对的消息。没有定义条目顺序。
TextMessage
:一种主体中包含
Java
字符串的消息(例如,
XML
消息)。
ObjectMessage
:一种主体中包含序列化
Java
对象的消息。
BytesMessage
:一种主体中包含连续字节流的消息。
JMS
支持两种消息传递模型
:点对点(
point-to-point
,简称
PTP
)和发布
/
订阅(
publish/subscribe
,简称
pub/sub
)。这两种消息传递模型非常相似,但有以下区别:
PTP
消息传递模型规定了一条消息只能传递给一个接收方。采用
javax.jms.Queue
表示。
Pub/sub
消息传递模型允许一条消息传递给多个接收方。采用
javax.jms.Topic
表示
这两种模型都通过扩展公用基类来实现。例如:
javax.jms.Queue
和
javax.jms.Topic
都扩展自
javax.jms.Destination
类。
P2P
P/S
配置目标位置
开始
JMS
编程前,我们需要先配置消息到达的目标地址
(Destination)
,因为只有目标地址存在了,我们才能发送消息到这个地址。由于每个应用服务器关于目标地址的配置方式都有所不同,下面以
jboss
为例,配置一个
queue
类型的目标地址。
<?xml version=”1.0″encoding=”UTF-8″?>
<server>
<
mbean
code=”
org.jboss.mq.server.jmx.Queue
”
name=”
jboss.mq.destination:service
=
Queue,name
=
foshanshop
“>
<attributename=”
JNDIName
“>
queue/
foshanshop
</attribute>
<dependsoptional-attribute-name=”
DestinationManager
“>
jboss.mq:service
=
DestinationManager
</depends>
</
mbean
>
</server>
Jboss
使用一个
XML
文件配置队列地址,文件的取名格式应遵守*
-service.xml
<attribute name=”
JNDIName
“>
属性指定了该目标地址的全局
JNDI
名称。如果你不指定
JNDIName
属性,
jboss
会为你生成一个默认的全局
JNDI
,其名称由“
queue”+“/”+
目标地址名称组成。另外在任何队列或主题被部署之前,应用服务器必须先部署
Destination Manager
Mbean
,所以我们通过
<depends>
节点声明这一依赖。
发送消息
一般发送消息有以下步骤:
(1)
得到一个
JNDI
初始化上下文
(Context)
InitialContext
ctx
= new
InitialContext
();
(2)
根据上下文查找一个连接工厂
QueueConnectionFactory
。该连接工厂是由
JMS
提供的,不需我们自己创建,每个厂商都为它绑定了一个全局
JNDI
,我们通过它的全局
JNDI
便可获取它;
QueueConnectionFactory
factory = (
QueueConnectionFactory
)
ctx.lookup
(”
QueueConnectionFactory
“);
(3)
从连接工厂得到一个连接
QueueConnection
conn
=
factory.createQueueConnection
();
(4)
通过连接来建立一个会话
(Session);
session =
conn.createQueueSession
(false,
QueueSession.AUTO_ACKNOWLEDGE
);
这句代码意思是:建立不需要事务的并且能自动确认消息已接收的会话。
(5)
查找目标地址:
例子对应代码:
Destination
destination
= (Destination )
ctx.lookup
(“queue/
foshanshop
“);
(6)
根据会话以及目标地址来建立消息生产者
MessageProducer
(
QueueSender
和
TopicPublisher
都扩展自
MessageProducer
接口)
例子对应代码:
MessageProducer
producer =
session.createProducer
(destination);
TextMessage
msg
=
session.createTextMessage
(”
您好,这是我的第一个消息驱动
Bean”);
producer.send
(
msg
);
采用消息驱动Bean接收消息
消息驱动
Bean(MDB)
是设计用来专门处理基于消息请求的组件。它和无状态
Session Bean
一样也使用了实例池技术,容器可以使用一定数量的
bean
实例
并发处理成百上千个
JMS
消息
。正因为
MDB
具有处理大量并发消息的能力,所以非常适合应用在一些消息网关产品。如果一个业务执行的时间很长,而执行结果无需实时向用户反馈时,也很适合使用
MDB
。如订单成功后给用户发送一封电子邮件或发送一条短信等。
一个
MDB
通常要实现
MessageListener
接口,该接口定义了
onMessage
()
方法。
Bean
通过它来处理收到的
JMS
消息。
package javax.jms;
public interface
MessageListener
{
public void
onMessage
(Message
message
);
}
当容器检测到
bean
守候的目标地址有消息到达时,容器调用
onMessage
()
方法,将消息作为参数传入
MDB
。
MDB
在
onMessage
()
中决定如何处理该消息。你可以使用注释指定
MDB
监听哪一个目标地址
(Destination)
。当
MDB
部署时,容器将读取其中的配置信息。
@
MessageDriven
(
activationConfig
=
{
@
ActivationConfigProperty
(
propertyName
=”
destinationType
“,
propertyValue
=”
javax.jms.Queue
“),
@
ActivationConfigProperty
(
propertyName
=”destination”,
propertyValue
=”queue/
foshanshop
“),
@
ActivationConfigProperty
(
propertyName
=”
acknowledgeMode
“,
propertyValue
=”Auto-acknowledge”)
})
public class
PrintBean
implements
MessageListener
{
public void
onMessage
(Message
msg
) {
WebService服务
Web
服务也是一种分布式技术,它与
EJB
最大的不同是,
Web
服务属于行业规范,可以跨平台及语言。而
EJB
属于
java
平台的规范,尽管理论上可以跨平台,但实现起来比较复杂,所以其应用范围局限在了
java
平台。看上去两者好像是互相竞争的关系,其实不是。它们两者的偏重点不一样,
Web
服务偏重的是这个系统对外提供什么功能,而
EJB
偏重的是如何
使
用一个个组件组装这些功能。就好比一个硬盘,它对外提供的是存储服务,这是
web
服务的关注点,对于怎样组装这个硬盘,怎样构造这些小零件,
web
服务并不关心,但这些却是
EJB
所关注的。
JavaEE
为
web service
提供了两种不同的编程模型:
EJB
容器模型及
Web
容器模型
,这里
将以最新的
JAX-WS2.x
规范(
Java API for XML-based Web Services
)介绍
webservice
的开发。
@
WebService
(
targetNamespace
=”http://ws.foshanshop.com”,
name = ”
HelloWorld
“,
serviceName
= ”
HelloWorldService
“)
客户端
开发步骤如下:
1.
在应用的类路径下放入
JAX-WS
的
jar
文件
(
下载路径
:
https://jax-ws.dev.java
.NET
)
。如果你使用的是
JDK6
,这一步可以省略,因为
JDK6
已经绑定了
JAX-WS
。目前
JDK6
绑定的
JAX-WS
版本是
2.0
。这意味着,当某些应用使用的
JAX-WS
版本高于
2.0
时,就有可能发生版本问题,这时,你需要升级
JDK6
中的
JAX-WS
版本,方法如下:
下载最高版本的
JAX-WS
,在产品
lib
目录中找到
jaxws-api.jar
和
jaxb-api.jar
,把这两个文件
copy
到
JDK6_HOME/
jre
/lib/endorsed
目录下。
如果有同学使用开发工具是
myeclipse
,
这时应该把
myeclipse
所使用的
jdk
更改为你系统安装的
jdk
。
2.
利用
Web Service
客户端生成工具生成辅助类。
3.
第三步:借助辅助类调用
web service
。
这里我们使用
wsimport
工具的
Ant
任务类生成辅助类
<?xml version=”1.0″encoding=”UTF-8″?>
<project name=”
WSClient
” default=”
wsclientgen
”
basedir
=”.”>
<propertyname=”src.dir” value=”${
basedir
}/
src
” />
<path id=”
build.classpath
“description=”
设置类路径
“>
<
fileset
dir=”${
basedir
}/lib”>
<includename=”*.jar”/>
</
fileset
>
</path>
<targetname=”
wsclientgen
“description=”
生成
webservice
客户端辅助代码,执行后请刷新项目
“>
<
taskdef
name=”
wsimport
”
classname
=”
com.sun.tools.ws.ant.WsImport
”
classpathref
=”
build.classpath
“/>
<
wsimport
wsdl
=”http://localhost:8080/WsHelloWorld/HelloWorldBean?wsdl”
sourcedestdir
=”${src.dir}” package=”
com.foshanshop.ws.client
“keep=”true”
verbose=”true”
destdir
=”${
basedir
}/bin”/>
</target>
</project>