On this page
32. JCA CCI
32.1 Introduction
Java EE 提供了一个规范来标准化对企业信息系统(EIS)的访问:JCA(Java EE 连接器体系结构)。该规范分为几个不同的部分:
连接器提供程序必须实现的 SPI(服务提供程序接口)。这些接口构成了资源适配器,可以将其部署在 Java EE 应用程序服务器上。在这种情况下,服务器将 Management 连接池,事务和安全性(托管模式)。应用服务器还负责 Management 配置,该配置保存在 Client 端应用程序外部。连接器也可以在没有应用程序服务器的情况下使用。在这种情况下,应用程序必须直接对其进行配置(非托管模式)。
应用程序可以用来与连接器交互并由此与 EIS 通信的 CCI(通用 Client 端接口)。还提供了用于本地事务划分的 API。
Spring CCI 支持的目的是提供类,以利用 Spring Framework 的常规资源和事务 Management 工具来访问典型的 Spring 风格的 CCI 连接器。
Note
连接器的 Client 端始终不使用 CCI。一些连接器公开自己的 API,仅提供 JCA 资源适配器以使用 Java EE 容器的系统协定(连接池,全局事务,安全性)。 Spring 没有为此类特定于连接器的 API 提供特殊支持。
32.2 配置 CCI
32.2.1 连接器配置
使用 JCA CCI 的基本资源是ConnectionFactory
接口。使用的连接器必须提供此接口的实现。
要使用连接器,可以将其部署在应用程序服务器上,并从服务器的 JNDI 环境(托管模式)中获取ConnectionFactory
。连接器必须打包为 RAR 文件(资源适配器 Files),并包含ra.xml
文件来描述其部署特性。资源的实际名称是在部署时指定的。要在 Spring 中访问它,只需使用 Spring 的JndiObjectFactoryBean
/<jee:jndi-lookup>
通过其 JNDI 名称获取工厂即可。
使用连接器的另一种方法是将其嵌入到您的应用程序中(非托管模式),而不使用应用程序服务器来部署和配置它。 Spring 提供了通过提供的FactoryBean
(LocalConnectionFactoryBean
)将连接器配置为 bean 的可能性。通过这种方式,您只需要在 Classpath 中使用连接器库(不需要 RAR 文件和ra.xml
Descriptors)。如有必要,必须从连接器的 RAR 文件中提取该库。
获得对ConnectionFactory
实例的访问权限后,可以将其注入到组件中。这些组件可以根据普通的 CCI API 进行编码,也可以利用 Spring 的支持类进行 CCI 访问(例如CciTemplate
)。
Note
在非托管模式下使用连接器时,不能使用全局事务,因为资源永远不会在当前线程的当前全局事务中被征用/除名。该资源根本不知道可能正在运行的任何全局 Java EE 事务。
Spring 中的 ConnectionFactory 配置
为了构建与 EIS 的连接,如果您处于托管模式,则需要从应用程序服务器获取ConnectionFactory
;如果处于非托管模式,则需要直接从 Spring 获取。
在托管模式下,您可以从 JNDI 访问ConnectionFactory
;其属性将在应用程序服务器中配置。
<jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/>
在非托管模式下,必须将要在 Spring 的配置中使用的ConnectionFactory
配置为 JavaBean。 LocalConnectionFactoryBean
类提供了这种设置样式,传入了连接器的ManagedConnectionFactory
实现,公开了应用程序级 CCI ConnectionFactory
。
<bean id="eciManagedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="tcp://localhost/"/>
<property name="portNumber" value="2006"/>
</bean>
<bean id="eciConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>
Note
您不能直接实例化特定的ConnectionFactory
。您需要为连接器完成ManagedConnectionFactory
接口的相应实现。该接口是 JCA SPI 规范的一部分。
32.2.3 配置 CCI 连接
JCA CCI 允许开发人员使用连接器的ConnectionSpec
实现来配置到 EIS 的连接。为了配置其属性,您需要使用专用适配器ConnectionSpecConnectionFactoryAdapter
包装目标连接工厂。因此,专用ConnectionSpec
可以配置为connectionSpec
属性(作为内部 bean)。
此属性不是必需的,因为 CCI ConnectionFactory
接口定义了两种不同的方法来获取 CCI 连接。某些ConnectionSpec
属性通常可以在应用程序服务器中(以托管模式)或在相应的本地ManagedConnectionFactory
实现中进行配置。
public interface ConnectionFactory implements Serializable, Referenceable {
...
Connection getConnection() throws ResourceException;
Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException;
...
}
Spring 提供了一个ConnectionSpecConnectionFactoryAdapter
,它允许指定一个ConnectionSpec
实例用于给定工厂的所有操作。如果指定了适配器的connectionSpec
属性,则适配器使用带有ConnectionSpec
参数的getConnection
变体,否则使用不带参数的变体。
<bean id="managedConnectionFactory"
class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory">
<property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="driverName" value="org.hsqldb.jdbcDriver"/>
</bean>
<bean id="targetConnectionFactory"
class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>
<bean id="connectionFactory"
class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<property name="connectionSpec">
<bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
<property name="user" value="sa"/>
<property name="password" value=""/>
</bean>
</property>
</bean>
32.2.4 使用单个 CCI 连接
如果要使用单个 CCI 连接,Spring 会提供另一个ConnectionFactory
适配器来 Management 此连接。 SingleConnectionFactory
适配器类将延迟打开单个连接,并在应用程序关闭时销毁该 bean 时将其关闭。此类将暴露具有相应行为的特殊Connection
代理,它们均共享相同的基础物理连接。
<bean id="eciManagedConnectionFactory"
class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TEST"/>
<property name="connectionURL" value="tcp://localhost/"/>
<property name="portNumber" value="2006"/>
</bean>
<bean id="targetEciConnectionFactory"
class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>
<bean id="eciConnectionFactory"
class="org.springframework.jca.cci.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetEciConnectionFactory"/>
</bean>
Note
无法使用ConnectionSpec
直接配置此ConnectionFactory
适配器。如果您需要特定ConnectionSpec
的单个连接,请使用SingleConnectionFactory
与之对话的中介ConnectionSpecConnectionFactoryAdapter
。
32.3 使用 Spring 的 CCI 访问支持
32.3.1 记录转换
JCA CCI 支持的目的之一是为处理 CCI 记录提供便利的设施。开发人员可以指定策略来创建记录并从 Logging 提取数据,以用于 Spring 的CciTemplate
。如果您不想直接在应用程序中使用记录,则以下界面将配置策略以使用 Importing 和输出记录。
为了创建 ImportingRecord
,开发人员可以使用RecordCreator
接口的专用实现。
public interface RecordCreator {
Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException;
}
如您所见,createRecord(..)
方法接收一个RecordFactory
实例作为参数,该实例与所使用的ConnectionFactory
的RecordFactory
相对应。该引用可用于创建IndexedRecord
或MappedRecord
实例。下面的示例演示如何使用RecordCreator
接口和索引/Map 的记录。
public class MyRecordCreator implements RecordCreator {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
IndexedRecord input = recordFactory.createIndexedRecord("input");
input.add(new Integer(id));
return input;
}
}
输出Record
可用于从 EIS 接收数据。因此,可以将RecordExtractor
接口的特定实现传递给 Spring 的CciTemplate
,以从输出Record
提取数据。
public interface RecordExtractor {
Object extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}
以下示例显示了如何使用RecordExtractor
界面。
public class MyRecordExtractor implements RecordExtractor {
public Object extractData(Record record) throws ResourceException {
CommAreaRecord commAreaRecord = (CommAreaRecord) record;
String str = new String(commAreaRecord.toByteArray());
String field1 = string.substring(0,6);
String field2 = string.substring(6,1);
return new OutputObject(Long.parseLong(field1), field2);
}
}
32.3.2 CciTemplate
CciTemplate
是核心 CCI 支持包(org.springframework.jca.cci.core
)的中心类。由于它处理资源的创建和释放,因此它简化了 CCI 的使用。这有助于避免常见的错误,例如忘记始终关闭连接。它关心连接和交互对象的生命周期,让应用程序代码专注于从应用程序数据生成 Importing 记录并从输出 Logging 提取应用程序数据。
JCA CCI 规范定义了两种不同的方法来调用 EIS 上的操作。 CCI Interaction
接口提供两个执行方法签名:
public interface javax.resource.cci.Interaction {
...
boolean execute(InteractionSpec spec, Record input, Record output) throws ResourceException;
Record execute(InteractionSpec spec, Record input) throws ResourceException;
...
}
根据调用的模板方法,CciTemplate
将知道在交互中要调用哪个execute
方法。无论如何,必须正确初始化InteractionSpec
实例。
CciTemplate.execute(..)
可以通过两种方式使用:
具有直接的
Record
参数。在这种情况下,您只需要传递 CCIImporting 记录,而返回的对象就是相应的 CCI 输出记录。对于应用程序对象,使用记录 Map。在这种情况下,您需要提供相应的
RecordCreator
和RecordExtractor
实例。
对于第一种方法,将使用以下模板方法。这些方法直接对应于Interaction
界面上的方法。
public class CciTemplate implements CciOperations {
public Record execute(InteractionSpec spec, Record inputRecord)
throws DataAccessException { ... }
public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord)
throws DataAccessException { ... }
}
使用第二种方法,我们需要指定记录创建和记录提取策略作为参数。使用的接口是上一部分有关记录转换的接口。相应的CciTemplate
方法如下:
public class CciTemplate implements CciOperations {
public Record execute(InteractionSpec spec,
RecordCreator inputCreator) throws DataAccessException {
// ...
}
public Object execute(InteractionSpec spec, Record inputRecord,
RecordExtractor outputExtractor) throws DataAccessException {
// ...
}
public Object execute(InteractionSpec spec, RecordCreator creator,
RecordExtractor extractor) throws DataAccessException {
// ...
}
}
除非在模板上设置了outputRecordCreator
属性(请参见下一节),否则每个方法都将使用两个参数调用 CCI Interaction
的相应execute
方法:InteractionSpec
和 ImportingRecord
,并接收输出Record
作为返回值。
CciTemplate
还提供了通过createIndexRecord(..)
和createMappedRecord(..)
方法在RecordCreator
实现之外创建IndexRecord
和MappedRecord
的方法。可以在 DAO 实现中使用它来创建Record
实例以传递到相应的CciTemplate.execute(..)
方法中。
public class CciTemplate implements CciOperations {
public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... }
public MappedRecord createMappedRecord(String name) throws DataAccessException { ... }
}
32.3.3 DAO 支持
Spring 的 CCI 支持为 DAO 提供了一个抽象类,支持注入ConnectionFactory
或CciTemplate
实例。该类的名称是CciDaoSupport
:它提供了简单的setConnectionFactory
和setCciTemplate
方法。在内部,此类将为传入的ConnectionFactory
创建一个CciTemplate
实例,并将其暴露给子类中的具体数据访问实现。
public abstract class CciDaoSupport {
public void setConnectionFactory(ConnectionFactory connectionFactory) {
// ...
}
public ConnectionFactory getConnectionFactory() {
// ...
}
public void setCciTemplate(CciTemplate cciTemplate) {
// ...
}
public CciTemplate getCciTemplate() {
// ...
}
}
32.3.4 自动输出记录生成
如果使用的连接器仅支持以 Importing 和输出记录作为参数的Interaction.execute(..)
方法(也就是说,它需要传递所需的输出记录,而不是返回适当的输出记录),则可以将CciTemplate
的outputRecordCreator
属性设置为自动收到响应后,将生成一个输出记录,以供 JCA 连接器填充。然后,该记录将返回给模板的调用者。
该属性仅包含用于该目的的RecordCreator
接口的实现。 RecordCreator
接口已经在第 32.3.1 节“记录转换”中讨论过。 outputRecordCreator
属性必须直接在CciTemplate
上指定。可以在应用程序代码中完成,如下所示:
cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator());
或(建议)在 Spring 配置中(如果CciTemplate
被配置为专用 bean 实例):
<bean id="eciOutputRecordCreator" class="eci.EciOutputRecordCreator"/>
<bean id="cciTemplate" class="org.springframework.jca.cci.core.CciTemplate">
<property name="connectionFactory" ref="eciConnectionFactory"/>
<property name="outputRecordCreator" ref="eciOutputRecordCreator"/>
</bean>
Note
由于CciTemplate
类是线程安全的,因此通常将其配置为共享实例。
32.3.5 Summary
下表总结了CciTemplate
类的机制以及在 CCI Interaction
接口上调用的相应方法:
表 32.1. 交互执行方法的用法
CciTemplate 方法签名 | CciTemplate outputRecordCreator 属性 | 在 CCI 交互上调用的 execute 方法 |
---|---|---|
记录执行(InteractionSpec,记录) | not set | 记录执行(InteractionSpec,记录) |
记录执行(InteractionSpec,记录) | set | boolean execute(InteractionSpec,Record,Record) |
无效执行(InteractionSpec,记录,记录) | not set | 无效执行(InteractionSpec,记录,记录) |
无效执行(InteractionSpec,记录,记录) | set | 无效执行(InteractionSpec,记录,记录) |
记录执行(InteractionSpec,RecordCreator) | not set | 记录执行(InteractionSpec,记录) |
记录执行(InteractionSpec,RecordCreator) | set | 无效执行(InteractionSpec,记录,记录) |
记录执行(InteractionSpec,Record,RecordExtractor) | not set | 记录执行(InteractionSpec,记录) |
记录执行(InteractionSpec,Record,RecordExtractor) | set | 无效执行(InteractionSpec,记录,记录) |
记录执行(InteractionSpec,RecordCreator,RecordExtractor) | not set | 记录执行(InteractionSpec,记录) |
记录执行(InteractionSpec,RecordCreator,RecordExtractor) | set | 无效执行(InteractionSpec,记录,记录) |
32.3.6 直接使用 CCI 连接和交互
CciTemplate
还提供了以与JdbcTemplate
和JmsTemplate
相同的方式直接处理 CCI 连接和交互的可能性。例如,当您要对 CCI 连接或交互执行多个操作时,此功能很有用。
接口ConnectionCallback
提供了一个 CCI Connection
作为参数,以便对其执行自定义操作,此外还提供了创建Connection
的 CCI ConnectionFactory
。例如,后者对于获取关联的RecordFactory
实例并创建索引/Map 记录很有用。
public interface ConnectionCallback {
Object doInConnection(Connection connection, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}
接口InteractionCallback
提供 CCI Interaction
,以便对其执行自定义操作,并提供相应的 CCI ConnectionFactory
。
public interface InteractionCallback {
Object doInInteraction(Interaction interaction, ConnectionFactory connectionFactory)
throws ResourceException, SQLException, DataAccessException;
}
Note
InteractionSpec
对象可以在多个模板调用之间共享,也可以在每个回调方法中重新创建。这完全取决于 DAO 的实现。
32.3.7 CciTemplate 用法示例
在本部分中,CciTemplate
的用法将显示为使用带有 IBM CICS ECI 连接器的 ECI 模式的 CICS。
首先,必须对 CCI InteractionSpec
进行一些初始化,以指定要访问的 CICS 程序以及如何与之交互。
ECIInteractionSpec interactionSpec = new ECIInteractionSpec();
interactionSpec.setFunctionName("MYPROG");
interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);
然后程序可以通过 Spring 的模板使用 CCI 并指定自定义对象和 CCI Records
之间的 Map。
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public OutputObject getData(InputObject input) {
ECIInteractionSpec interactionSpec = ...;
OutputObject output = (ObjectOutput) getCciTemplate().execute(interactionSpec,
new RecordCreator() {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
return new CommAreaRecord(input.toString().getBytes());
}
},
new RecordExtractor() {
public Object extractData(Record record) throws ResourceException {
CommAreaRecord commAreaRecord = (CommAreaRecord)record;
String str = new String(commAreaRecord.toByteArray());
String field1 = string.substring(0,6);
String field2 = string.substring(6,1);
return new OutputObject(Long.parseLong(field1), field2);
}
});
return output;
}
}
如前所述,回调可用于直接在 CCI 连接或交互上工作。
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public OutputObject getData(InputObject input) {
ObjectOutput output = (ObjectOutput) getCciTemplate().execute(
new ConnectionCallback() {
public Object doInConnection(Connection connection,
ConnectionFactory factory) throws ResourceException {
// do something...
}
});
}
return output;
}
}
Note
对于ConnectionCallback
,将使用CciTemplate
来 Management 和关闭所使用的Connection
,但是在连接上创建的任何交互都必须由回调实现来 Management。
对于更具体的回调,您可以实现InteractionCallback
。在这种情况下,传入的Interaction
将由CciTemplate
Management 和关闭。
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public String getData(String input) {
ECIInteractionSpec interactionSpec = ...;
String output = (String) getCciTemplate().execute(interactionSpec,
new InteractionCallback() {
public Object doInInteraction(Interaction interaction,
ConnectionFactory factory) throws ResourceException {
Record input = new CommAreaRecord(inputString.getBytes());
Record output = new CommAreaRecord();
interaction.execute(holder.getInteractionSpec(), input, output);
return new String(output.toByteArray());
}
});
return output;
}
}
对于上面的示例,在非托管模式下,所涉及的 Spring Bean 的相应配置如下所示:
<bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="local:"/>
<property name="userName" value="CICSUSER"/>
<property name="password" value="CICS"/>
</bean>
<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>
<bean id="component" class="mypackage.MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
在托管模式下(即,在 Java EE 环境中),配置可能如下所示:
<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
32.4 将 CCI 访问建模为操作对象
org.springframework.jca.cci.object
软件包包含支持类,这些支持类允许您以不同的方式访问 EIS:通过可重用的操作对象,类似于 Spring 的 JDBC 操作对象(请参阅 JDBC 章)。这通常将封装 CCI API:将应用程序级 Importing 对象传递给操作对象,以便它可以构造 Importing 记录,然后将接收到的记录数据转换为应用程序级输出对象并返回它。
Note
这种方法在内部基于CciTemplate
类和RecordCreator
/RecordExtractor
接口,重用了 Spring 核心 CCI 支持的机制。
32.4.1 MappingRecordOperation
MappingRecordOperation
本质上与CciTemplate
执行相同的工作,但是将特定的预配置操作表示为对象。它提供了两种模板方法来指定如何将 Importing 对象转换为 Importing 记录,以及如何将输出记录转换为输出对象(记录 Map):
createInputRecord(..)
指定如何将 Importing 对象转换为 ImportingRecord
extractOutputData(..)
指定如何从输出Record
中提取输出对象
这些是这些方法的签名:
public abstract class MappingRecordOperation extends EisOperation {
...
protected abstract Record createInputRecord(RecordFactory recordFactory,
Object inputObject) throws ResourceException, DataAccessException {
// ...
}
protected abstract Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException, DataAccessException {
// ...
}
...
}
此后,为了执行 EIS 操作,您需要使用单个 execute 方法,传入应用程序级 Importing 对象并接收应用程序级输出对象作为结果:
public abstract class MappingRecordOperation extends EisOperation {
...
public Object execute(Object inputObject) throws DataAccessException {
}
...
}
如您所见,与CciTemplate
类相反,此execute(..)
方法没有InteractionSpec
作为参数。相反,InteractionSpec
对操作是全局的。必须使用以下构造函数实例化具有特定InteractionSpec
的操作对象:
InteractionSpec spec = ...;
MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec);
...
32.4.2 MappingCommAreaOperation
一些连接器使用基于 COMMAREA 的记录,该记录表示一个字节数组,其中包含要发送到 EIS 的参数和它返回的数据。 Spring 提供了一个特殊的操作类,可以直接在 COMMAREA 上工作而不是在记录上工作。 MappingCommAreaOperation
类扩展了MappingRecordOperation
类以提供这种特殊的 COMMAREA 支持。它隐式地使用CommAreaRecord
类作为 Importing 和输出记录类型,并提供了两种新方法将 Importing 对象转换为 ImportingCOMMAREA,并将输出 COMMAREA 转换为输出对象。
public abstract class MappingCommAreaOperation extends MappingRecordOperation {
...
protected abstract byte[] objectToBytes(Object inObject)
throws IOException, DataAccessException;
protected abstract Object bytesToObject(byte[] bytes)
throws IOException, DataAccessException;
...
}
32.4.3 自动输出记录生成
由于每个MappingRecordOperation
子类内部都基于 CciTemplate,因此可以使用与CciTemplate
相同的自动生成输出记录的方式。每个操作对象都提供相应的setOutputRecordCreator(..)
方法。有关更多信息,请参见第 32.3.4 节“自动输出记录生成”。
32.4.4 Summary
操作对象方法以与CciTemplate
类相同的方式使用记录。
表 32.2. 交互执行方法的用法
MappingRecordOperation 方法签名 | MappingRecordOperation outputRecordCreator 属性 | 在 CCI 交互上调用的 execute 方法 |
---|---|---|
Object execute(Object) | not set | 记录执行(InteractionSpec,记录) |
Object execute(Object) | set | boolean execute(InteractionSpec,Record,Record) |
32.4.5 MappingRecordOperation 用法示例
在本节中,将显示MappingRecordOperation
的用法以使用 Blackbox CCI 连接器访问数据库。
Note
该连接器的原始版本由 Java EE SDK(1.3 版)提供,可从 Oracle 获得。
首先,必须对 CCI InteractionSpec
进行一些初始化以指定要执行的 SQL 请求。在此示例中,我们直接定义了将请求的参数转换为 CCI 记录的方法以及将 CCI 结果记录转换为Person
类的实例的方法。
public class PersonMappingOperation extends MappingRecordOperation {
public PersonMappingOperation(ConnectionFactory connectionFactory) {
setConnectionFactory(connectionFactory);
CciInteractionSpec interactionSpec = new CciConnectionSpec();
interactionSpec.setSql("select * from person where person_id=?");
setInteractionSpec(interactionSpec);
}
protected Record createInputRecord(RecordFactory recordFactory,
Object inputObject) throws ResourceException {
Integer id = (Integer) inputObject;
IndexedRecord input = recordFactory.createIndexedRecord("input");
input.add(new Integer(id));
return input;
}
protected Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException {
ResultSet rs = (ResultSet) outputRecord;
Person person = null;
if (rs.next()) {
Person person = new Person();
person.setId(rs.getInt("person_id"));
person.setLastName(rs.getString("person_last_name"));
person.setFirstName(rs.getString("person_first_name"));
}
return person;
}
}
然后,应用程序可以使用人员标识符作为参数来执行操作对象。请注意,操作对象可以设置为共享实例,因为它是线程安全的。
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public Person getPerson(int id) {
PersonMappingOperation query = new PersonMappingOperation(getConnectionFactory());
Person person = (Person) query.execute(new Integer(id));
return person;
}
}
在非托管模式下,Spring Bean 的相应配置如下所示:
<bean id="managedConnectionFactory"
class="com.sun.connector.cciblackbox.CciLocalTxManagedConnectionFactory">
<property name="connectionURL" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="driverName" value="org.hsqldb.jdbcDriver"/>
</bean>
<bean id="targetConnectionFactory"
class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>
<bean id="connectionFactory"
class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<property name="connectionSpec">
<bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
<property name="user" value="sa"/>
<property name="password" value=""/>
</bean>
</property>
</bean>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
在托管模式下(即,在 Java EE 环境中),配置可能如下所示:
<jee:jndi-lookup id="targetConnectionFactory" jndi-name="eis/blackbox"/>
<bean id="connectionFactory"
class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<property name="connectionSpec">
<bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
<property name="user" value="sa"/>
<property name="password" value=""/>
</bean>
</property>
</bean>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
32.4.6 MappingCommAreaOperation 用法示例
在本部分中,将显示MappingCommAreaOperation
的用法:使用 IBM CICS ECI 连接器以 ECI 模式访问 CICS。
首先,需要初始化 CCI InteractionSpec
以指定要访问哪个 CICS 程序以及如何与之交互。
public abstract class EciMappingOperation extends MappingCommAreaOperation {
public EciMappingOperation(ConnectionFactory connectionFactory, String programName) {
setConnectionFactory(connectionFactory);
ECIInteractionSpec interactionSpec = new ECIInteractionSpec(),
interactionSpec.setFunctionName(programName);
interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);
interactionSpec.setCommareaLength(30);
setInteractionSpec(interactionSpec);
setOutputRecordCreator(new EciOutputRecordCreator());
}
private static class EciOutputRecordCreator implements RecordCreator {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
return new CommAreaRecord();
}
}
}
然后可以将抽象EciMappingOperation
类作为子类,以指定自定义对象和Records
之间的 Map。
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public OutputObject getData(Integer id) {
EciMappingOperation query = new EciMappingOperation(getConnectionFactory(), "MYPROG") {
protected abstract byte[] objectToBytes(Object inObject) throws IOException {
Integer id = (Integer) inObject;
return String.valueOf(id);
}
protected abstract Object bytesToObject(byte[] bytes) throws IOException;
String str = new String(bytes);
String field1 = str.substring(0,6);
String field2 = str.substring(6,1);
String field3 = str.substring(7,1);
return new OutputObject(field1, field2, field3);
}
});
return (OutputObject) query.execute(new Integer(id));
}
}
在非托管模式下,Spring Bean 的相应配置如下所示:
<bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="local:"/>
<property name="userName" value="CICSUSER"/>
<property name="password" value="CICS"/>
</bean>
<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
在托管模式下(即,在 Java EE 环境中),配置可能如下所示:
<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
32.5 Transactions
JCA 为资源适配器指定了多个级别的事务支持。资源适配器支持的事务类型在其ra.xml
文件中指定。基本上有三个选项:无(例如,使用 CICS EPI 连接器),本地事务(例如,使用 CICS ECI 连接器),全局事务(例如,使用 IMS 连接器)。
<connector>
<resourceadapter>
<!-- <transaction-support>NoTransaction</transaction-support> -->
<!-- <transaction-support>LocalTransaction</transaction-support> -->
<transaction-support>XATransaction</transaction-support>
<resourceadapter>
<connector>
对于全局事务,可以使用 Spring 的通用事务基础结构来划分事务,以JtaTransactionManager
作为后端(委托给下面的 Java EE 服务器的分布式事务处理协调器)。
对于单个 CCI ConnectionFactory
上的本地事务,Spring 为 CCI 提供了一种特定的事务 Management 策略,类似于 JDBC 的DataSourceTransactionManager
。 CCI API 定义了本地事务对象和相应的本地事务划分方法。 Spring 的CciLocalTransactionManager
执行此类本地 CCI 事务,完全符合 Spring 的通用PlatformTransactionManager
抽象。
<jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/>
<bean id="eciTransactionManager"
class="org.springframework.jca.cci.connection.CciLocalTransactionManager">
<property name="connectionFactory" ref="eciConnectionFactory"/>
</bean>
两种 Transaction 策略都可以与 Spring 的任何 Transaction 标界工具一起使用,无论是声明式还是程序式。这是 Spring 通用的PlatformTransactionManager
抽象的结果,该抽象将事务划分与实际执行策略分离。只需根据需要在JtaTransactionManager
和CciLocalTransactionManager
之间切换,即可保持事务划分不变。
有关 SpringTransaction 功能的更多信息,请参见标题为第十七章,TransactionManagement的章节。