开发单独会话 Bean
为 Enterprise JavaBeans (EJB) 3.1 规范所引进的单独会话 Bean 创建 Bean 实现类。EJB 容器仅初始化单独会话 Bean 的一个实例,该实例由所有客户机共享。由于单个实例由所有客户机共享,所以单独会话 Bean 有特殊的生命周期和并行语义。
开始之前
关于此任务
public interface Configuration {
Object get(String name);
void set(String name, Object value);
}
@Singleton
public class ConfigurationBean implements Configuration {
private Map<String, Object> settings = new HashMap<String, Object>();
public Object get(String name) {
return settings.get(name);
}
public void set(String name, Object value) {
System.out.println(e);
}
}
和其他企业 Bean 类型一样,您也可以在部署描述符中(而不是使用注释)声明单独会话 Bean 的元数据;例如:
<?xml version="1.0"?>
<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_1.xsd"
version="3.1"
>
<enterprise-Beans>
<ejb-name>ConfigurationBean</ejb-name>
<business-local>com.ibm.example.Configuration</business-local>
<ejb-class>com.ibm.example.ConfigurationBean</ejb-class>
<session-type>Singleton</session-type>
</enterprise-beans>
</ejb-jar>
过程
- 编码初始化和破坏方法,从而了解它们是如何与用于设置事务上下文的选项相关的。 初始化期间,会创建实例,进行依赖关系注入以及启动 PostConstruct 生命周期拦截器回调。如果停止单独会话 Bean 的包含应用程序,那么会针对单独会话 Bean 启动 PreDestroy 生命周期拦截器回调。
这对于在 PostConstruct 和 PreDestroy 生命周期拦截器回调期间完成事务性活动可能有用。出于此原因,单独会话 Bean 生命周期拦截器回调具有明确定义的事务上下文。下列事务上下文值类似于 @Timeout 方法:只能使用 REQUIRED(缺省值)、REQUIRES_NEW 以及 NOT_SUPPORTED,并且会将 REQUIRED 转换为 REQUIRES_NEW。
仅当对 Bean 类上的生命周期拦截器方法指定事务属性时,才能识别这些事务属性。会对所有生命周期拦截器使用同一个事务上下文。以下示例说明了具有对 PostConstruct 和 PreDestroy 生命周期拦截器回调指定的事务属性的单独会话 Bean。
@Singleton public class ConfigurationBean implements Configuration { @PostConstruct @TransactionAttribute(REQUIRED) // the default; specified for illustration public void initialize() { // ... } @PreDestroy @TransactionAttribute(NOT_SUPPORTED) public void destroy() { // ... } // ... }
可以使用 XML 部署描述符(而不是使用注释)来指定相同的元数据。如果在 XML 部署描述符中指定事务属性,那么会忽略从 @TransactionAttribute 注释获取的任何元数据。以下示例使用 XML 部署描述符来指定与上一个示例相同的元数据。
<assembly-descriptor> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>initialize</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>destroy</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor>
- 除非另有说明,通过单独会话 Bean 的其中一个客户机视图对它第一次进行使用时,通常会初始化单独会话 Bean 实例。 使用 @Startup 注释或相应的 XML 部署描述符来将 Bean 标记为启动 Bean。如果将单独 Bean 标记为启动 Bean,那么表示 EJB 容器必须先运行 PostConstruct 方法,然后才能支持任何外部客户机对要运行的应用程序发出的请求。单独 Bean 中的 PostConstruct 方法可以创建 EJB 计时器,将消息添加至 JMS 队列或主题,调用异步 EJB 方法,或者启动其他对 EJB 进行调用的异步机制。然而,为了避免死锁,PostConstruct 方法不能等待 EJB 计时器运行,也不能等待对消息驱动的 Bean 方法进行调用或者异步 EJB 方法完成。
应用程序开发者可以将业务逻辑放入这些启动单独实例的 PostConstruct 方法中,以完成容器启动任何客户机工作之前必须执行的任务,例如预装入高速缓存或启动应用程序中的异步工作。
以下示例说明了具有启动初始化的单独会话 Bean:
@Singleton @Startup public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // 1. Create the database table if it does not exist. // 2. Initialize settings from the database table. // 3. Load a cache. // 4. Initiate asynchronous work (for example, work to a messaging queue or to // calls to asynchronous session Bean methods. } // ... }
可以使用 XML 部署描述符(而不是使用注释)来指定相同的元数据。指定 true 以将此单独 Bean 标记为启动单项。相反地,指定 false;如果类文件上存在 @Startup 注释,那么会将该注释覆盖。
<session> <ejb-name>ConfigurationBean</ejb-name> <init-on-startup>true</init-on-startup> </session>
- 确定单独会话 Bean 的初始化方法是否对其他单独会话 Bean 具有隐式依赖性。
如果存在隐式依赖性,请使用依赖性元数据将隐式依赖性变成显式依赖性。容器会确保依赖性单独 Bean 在其从属 Bean 之前进行初始化,并且在其从属 Bean 之后加以破坏。以下示例说明了具有依赖性元数据的单独会话 Bean:
@Singleton public class DatabaseBean { @PostConstruct public void initialize() { // Create database tables. } } @Singleton @DependsOn({"DatabaseBean"}) public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // Initialize settings from a database table. } // ... }
此外,还可以通过使用 EJB 链接 module.jar#bean 语法来建立跨模块依赖性。循环依赖性不受支持,而且会导致应用程序失败。
可以使用 XML 部署描述符(而不是使用注释)来指定相同的元数据。如果在 XML 部署描述符中指定依赖性元数据,那么会忽略来自 @DependsOn 注释的任何元数据。
<session> <ejb-name>ConfigurationBean</ejb-name> <depends-on> <ejb-name>DatabaseBean</ejb-name> </depends-on> </session>
- 决定使用容器管理的并行还是 Bean 管理的并行。 使用 Bean 管理的并行时,@Lock 和 @AccessTimeout 注释不适用。
只能在单独会话 Bean 类上实现 @ConcurrencyManagement 注释。它不能用在它扩展的类上或者类继承树中更高级别的类中。
以下代码示例说明了具有 Bean 管理的并行的单项:@Singleton @ConcurrencyManagement(BEAN) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); synchronized public Object get(String name) { return settings.get(name); } synchronized public void set(String name, Object value) { settings.put(name, value); } }
可以使用 XML 部署描述符(而不是使用注释)来指定相同的元数据。如果元数据既在 XML 部署描述符中指定,也使用 @ConcurrencyManagement 注释来指定,那么该值必须匹配,否则应用程序会失败。以下示例使用 XML 部署描述符来指定与上一个示例相同的元数据。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrency-management-type>Bean</concurrency-management-type> </session>
容器不会对所调用的每个方法进行锁定。相反地,实际 Bean 会负责需要的锁定。在该示例中,Bean 提供程序已选择使用同步关键字来实现方法。具有 Bean 管理的并行的单独会话 Bean 支持这样做,但其他 EJB 组件类型不支持这样做。Bean 提供程序并非必须使用同步关键字来提供并行。例如,Bean 提供程序可以使用 JDK 5 及更高版本中的 java.util.concurrent.locks.ReentrantReadWriteLock 类。
容器管理的并行 EJB 3.1 规范所需的锁定语义与 java.util.concurrent.locks.ReentrantReadWriteLock 类的行为相匹配。
- 如果正在使用容器管理的并行,请使用 @Lock 注释来管理方法的并行。 以下代码示例说明了具有容器管理的并行的 singleton。
@Singleton public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); @Lock(READ) public Object get(String name) { return settings.get(name); } public void set(String name, Object value) { settings.put(name, value); } }
可以使用 XML 部署描述符(而不是使用注释)来指定相同的元数据。如果元数据既在 XML 部署描述符中指定,也使用 @Lock 注释来指定,那么会忽略从 @Lock 注释获取的元数据。以下示例使用 XML 部署描述符来指定与上一个示例相同的元数据。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> </concurrent-method> </session>
该示例还说明了使用 @Lock(READ) 对方法进行注释以指示启动该方法时容器必须获取读锁定。使用 @Lock 注释方法时,该注释会覆盖在类级别指定的 @Lock 注释。 没有类级别的 @Lock 注释时,缺省值为写锁定。在该示例中,方法上的 @Lock(READ) 覆盖了类级别的缺省写锁定。 未在方法级别注释方法并且没有类级别的任何注释时,容器会使用缺省写锁定。
因为大多数方法需要读锁定,所以请使用类级别的 @Lock(READ) 来指示此类中的所有业务方法都要求容器获取读锁定。 对于需要写锁定的方法,请使用 @Lock(WRITE) 来注释这些方法以表示它会覆盖在类级别指定的读锁定。
以下示例说明了此技巧:
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); public Object get(String name) { return settings.get(name); } @Lock(WRITE) public void set(String name, Object value) { settings.put(name, value); } }
@Lock 注释仅适用于在 @Lock 注释所在的同一个类中声明的方法。对于给定类,@Lock 的元数据绝不会从类继承树中更高级别的类进行继承。可以在 XML 部署描述符中使用可匹配所有方法的特殊方法名 *(而不是在类级别使用注释)来指定相同的元数据。
- 如果您正在使用容器管理的并行,那么使用 @AccessTimeout 注释来限制方法等待授予其锁定的时间。 以下代码示例说明了并行存取超时。
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) @AccessTimeout(1000) public Object get(String name) { // query the database } public void set(String name, Object value) { // update the database } }
如果未提供注释,那么方法的缺省行为是等待,直到系统授予其锁定为止。客户机等待授予其锁定时没有时间限制。因为未在类级别编码任何内容,所以等待锁定被授予类的所有方法时没有时间限制。 如果使用了 @AccessTimeout 注释且容器在指定的时间限制内无法授予锁定,那么会对客户机抛出 javax.ejb.ConcurrentAccessTimeoutException。@AccessTimeout 注释仅适用于在 @AccessTimeout 注释所在的同一个类中声明的方法。对于给定类,@AccessTimeout 注释的元数据绝不会从类继承树中更高级别的类进行继承。
类似于 @Lock 注释,您也可以使用 XML 部署描述符来指定 @AccessTimeout 注释,而且如果使用 XML 部署描述符,那么会忽略来自 @AccessTimeout 注释的元数据。以下示例使用 XML 部署描述符来指定与上一个示例相同的元数据。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>1000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
- 重要的是,了解 concurrent-methodType 的 XML 编码遵循在 EJB 规范中概述的有关撰写容器事务方法元素的 XML 的三种样式。
请记住,lock 元素和 access-timeout 元素是可选的。这三种样式如下所述:
样式 1 使用特殊方法名 * 将锁定类型和/或 access-timeout 值应用到所指定 Bean 的所有业务方法。
<!-- Example: Style 1 --> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
使用样式 2 以特定名称来引用业务方法,并将所指定的锁定类型和/或 access-timeout 值指定给业务方法。如果方法名是重载的方法名,那么表明多种方法的名称相同,只是方法特征符不同,并且所有具有此名称的方法都具有指定的锁定类型和/或 access-timeout 值。样式 2 优先于样式 1。
<!-- Example: Style 2 --> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
使用样式 3 来引用不同的方法,此方法与给定方法名匹配且具有的方法特征符与列出的方法参数匹配。样式 3 优先于样式 1 和样式 2。
<!-- Example: Style 3 --> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
如果使用样式 1 XML 来定义锁定类型,那么会忽略 Bean 上的所有 @Lock 注释。对于超时访问也同样如此。如果使用样式 1 XML 来定义访问超时值,那么会忽略 Bean 上的所有 @AccessTimeout 注释。
- 了解 @Lock 注释和 @AccessTimeout 注释以相互独立的方式,根据各自的相应 XML 部署描述符代码进行处理很重要。
此概念的实现具有多种好处。这种将锁定类型和访问超时分离的方式不要求您知道锁定类型,这样有助于防止对黑匣应用程序代码造成负面影响。您可以安全地保留锁定类型值并仅调整访问超时值以适合环境需求,而且避免可能的死锁情况或其他并行问题。
设想一种情况,您正在运行供应商提供的 EJB 应用程序,但由于系统变慢,该应用程序不断超时。因为担心会造成死锁情况,所以您不想更改锁定逻辑,但您确实想要修改超时限制。您可以编辑部署描述符,并对您想要修改的方法指定所需的访问超时值。以下示例显示如何在 Bean 实现中仅指定方法级别 @Lock(READ) 注释,以及使用样式 2 来编写 XML 以将 access-timeout 元素指定为 2,000 毫秒,而不是提供可选的 lock 元素。结果是一个具有读取锁定的方法,该锁定的访问超时值为 2,000 毫秒。
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) public Object businessMethod(long value) { // ... } // ... }
类似地,您可以使用类级别锁定注释,然后在 XML 中使用样式 2 和/或样式 3 来指定想要的访问超时值,如以下示例中所示。<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } public Object businessMethod(long value, int i, Object value) { // ... } public Object businessMethod(long value, int i) { // ... } }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <access-timeout> <timeout>8000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上一个代码示例会生成所有名称为“businessMethod”的方法,这些方法的锁定类型为读取,并且访问超时值为 2,000 毫秒。不同之处在于方法“businessMethod”的一个实例具有方法特征符,该特征符的第一个参数的类型为 long,而第二个参数的类型为 int。方法“businessMethod”的此实例的锁定类型为读取,但访问超时值为 8,000 毫秒。
如果使用样式 1 XML 来仅定义锁定类型,而不定义访问超时值,那么适用相同的原则。可以使用样式 2 和/或样式 3 将访问超时值添加至特定方法,以获取特定锁定类型和访问超时值结果。以下示例说明了这一点:<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上一个代码示例生成的所有业务方法都具有读取锁定类型,并且访问超时值为 2,000 毫秒。
您还可以使用类级别 @Lock 注释来设置所有方法的锁定类型,并使用样式 1 来编写 XML 以仅设置所有方法的访问超时值。请参阅以下示例:@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } // ... }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上一个示例会生成 Bean (ConfigurationBean) 的所有业务方法,这些方法的锁定类型为读取,并且访问超时值为 2,000 毫秒。
- 确保您了解所使用注释的继承规则。
- 避免在同一个单独会话 Bean 中读取锁定方法调用写入锁定方法时可能发生的可重入锁定行为。
假定单独会话 Bean 的业务方法直接或间接导致启动单独会话 Bean 的另一个业务方法。如果第一个方法是写入锁定方法,那么该方法可以调用单独会话 Bean 的任何其他业务方法,而不必考虑任何特殊事项。然而,您可能仔细地实现了读取锁定方法,但如果读取锁定方法要调用同一个单独会话 Bean 类的另一个业务方法(该方法是写入锁定方法),就会发生 javax.ejb.IllegalLoopbackException 异常。
子主题
更改独立会话 Bean 锁定策略
使用此任务可覆盖服务器中所有单独会话 Bean 写锁定的缺省非公平锁定策略。 该任务适用于下列 WebSphere® Application Server 用户:不希望锁定请求,以便其单独会话 Bean 方法调用遵循非公平策略。更改独立会话 Bean 锁定策略
使用此任务可覆盖服务器中所有单独会话 Bean 写锁定的缺省非公平锁定策略。 该任务适用于下列 WebSphere Application Server 用户:不希望锁定请求,以便其单独会话 Bean 方法调用遵循非公平策略。


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_ssb
文件名:tejb_ssb.html