Session Bean分为有状态Bean和无状态Bean,有状态Bean可以维护会话状态,无状态会话Bean不维护会话状态。开发一个Session Bean需要定义接口和Bean Class,其中接口分为远程(remote)和本地(Local)接口。EJB3.0不要求同时实现remote和local接口,但一般两者同时实现。EJB容器之外的应用要访问EJB只能通过remote接口,容器内的应用通过local接口和remote接口都可以访问,但使用local接口性能更好。
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C05%5Cclip_filelist.xml">
- Stateless Session Bean (无状态会话Bean)
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C09%5Cclip_filelist.xml">
1. 无状态会话Bean不维护会话状态,一个Bean实例可以为多个用户服务,EJB容器使用实例池化技术管理无状态会话Bean。
2. 只实现Remote接口的无状态Session Bean
@Stateless
@Remote(MyHelloWorld.class)
public class MyHelloWorldBean implements MyHelloWorld {……}
3. @Stateless的定义
Package javax.ejb;
@Target(TYPE)
@Retention(RUNTIME)
Public @interface Stateless{
String name() default “”;
String mappedName default “”;
}
- name()属性指定Session Bean的EJB名称,该名称在EJB jar包中必须是全局唯一的,而在EAR中却可以重复,因为EAR可以包含多个EJB jar,每个jar包中可以存在一个与其他jar包中同名的EJB。在EAR中定位某个EJB可以这样使用:xxx.jar#MyHelloWorldBean。该属性默认为Bean Class的类名(不带包名)。
- mappedName()属性指定Bean的全局JNDI名称,这个属性在WebLogic、Sun应用服务器和glassfish起作用。
- @Stateless注释指定Session Bean的remote接口,Bean类有多个remote接口时用大括号将接口括起来,接口之间用逗号分隔,
如 @remote({A.class,B.class,C.class})
4. Session bean开发完后打成jar包进行部署,可以使用Eclipse或者Ant进行打包任务。部署完后可以通过客户端进行访问。
- 如果把EJB作为模块打包进*.ear的Java EE企业应用文件,默认的全局JNDI名称如下:
本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local
远程接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote
例如:将MyHelloWorld应用作为EJB模块(jar包)打包进MyHelloWorld.ear,它的远程接口的JNDI名称为:MyHelloWorld/MyHelloWorldBean/remote。
- 如果EJB应用打包进*.jar模块文件,默认的全局JNDI名称如下:
本地接口: EJB-CLASS-NAME/local
远程接口: EJB-CLASS-NAME/remote
例如:将MyHelloWorld应用打包成MyHelloWorld.jar文件,它的远程接口的JNDI名称为: MyHelloWorldBean/remote
5. EJB发布成功后,可以通过客户端进行访问,EJB发布在JBoss时,可以这样访问:
<%@ page language="java" import="java.util.Properties,javax.naming.*,com.csu.ejb3.MyHelloWorld" pageEncoding="GBK"%>
<%
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);
MyHelloWorld myHello = (MyHelloWorld)ctx.lookup("MyHelloWorldBean/remote");
out.println(myHello.sayHello("湖南"));
} catch (NamingException e) {
out.println(e.getMessage());
}
%>- 如果客户端应用与EJB运行在同一个服务器内,则创建InitialContext 对象时不需要传递参数且客户端应用不需要包含用到的远程接口类以及实体类。
- 如果客户端应用与EJB运行在不同的服务器,则创建InitialContext 对象时需要传递Properties 类型的参数,并且客户端应用需要包含用到的远程接口类和实体类(如果用到了实体的话),同时还要包含JBoss提供的客户端jar文件%JBoss_Home%/client/ jbossall-client.jar(不过最好包含该目录下所有的jar文件,如果没有包含该jar文件,客户端访问EJB时会发生EJB异常:Cannot instantiate class: org.jnp.interfaces.NamingContextFactory)。
- 调用EJB时,如果客户端和EJB不在同一个jvm,就要设置InitialContext的参数,不同的应用服务器InitialContext写法也不同.
Context.INITIAL_CONTEXT_FACTORY:指定到目录服务的连接工厂
Context.PROVIDER_URL:目录服务提供者URL
//JBoss:
Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"
Context.URL_PKG_PREFIXES, "org.jboss.naming"
Context.PROVIDER_URL, "localhost:1099"
//Weblogic:
Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"
Context.PROVIDER_URL, "t3://localhost:7001"
6. 只实现Local接口的无状态Session Bean
@Stateless
@Local({MyLocalHelloWorld.class})
public class MyLocalHelloWorldBean implements MyLocalHelloWorld {….}
- 和@Remote注释一样,@Local注释也可以定义多个本地接口,如:@Local({A.class,B.class,C.class}),只有一个接口时可以省略大括号。
- 不能在应用服务器外调用Local接口,如果客户端应用与EJB容器不在同一个JVM,则只能通过Remote接口进行访问。
7. 实现了Local接口和Remote接口的无状态Session Bean
@Stateless
@Remote(Operation.class)
@Local(LocalOperation.class)
public class OperationBean implements LocalOperation, Operation {…}
8 EJB容器使用实例池管理无状态Session Bean,使系统的吞吐量增大,类似于数据库连接池管理数据库连接对象。
Stateless Session Bean 的生命周期只有两个状态: does not exist 和 method-ready pool 。