J2EE 连接器(JCA)是一种企业级应用整合的技术。目前,在 J2EE 平台中,常使用的应用整合的技术有:
- Java 消息服务(JMS);
- Web 服务(Web Services);
- J2EE 连接器体系结构(JCA)。
Java 消息服务是一组在 Java 程序中使用企业级消息的 API,它为整合 J2EE 应用和非 J2EE 应用程序提供了异步整合的方式,在这种方式里,所有的应用都和消息中间件(MOM)进行通信,这样就提供了与平台无关、语言无关的整合。Web 服务是一种新兴发展起来的技术,它使用 SOAP 消息作为传输的载体,使用 HTTP 或者其它基于文本的协议作为数据传输的协议,Web 服务可以是同步的整合,也可以进行异步的整合。同样,Web 服务也是一种和平台无关、和开发语言无关的整合技术。
J2EE 连接器技术为连接 J2EE 应用服务器和已有的企业应用系统(ERP/CRM 等)提供了解决方案。通过 J2EE 连接器,EIS(企业信息系统)厂商不需要再为每个应用服务器提供专门的支持接口,同样,应用服务器厂商在连接到新的 EIS 系统时也不需要再重新开发新的代码,JCA 为整合企业资源提供了标准的解决方案。
在 JCA1.0 规范中,它定义了应用服务器和资源适配器的系统级合同(连接池、事务管理和安全),为资源适配器的客户端定义了通用的客户端接口(Common Client Interface,CCI),同样也规范了 JCA 打包和部署等细节。但在 JCA1.0 规范中,只支持 OutBound 的调用,也就是说只能在 J2EE 应用中通过资源适配器向外调用企业资源层,而企业资源层不能通过适配器调用 J2EE 里的资源。在即将发布的 JCA1.5 规范中,这个问题得到了解决,也就是说,在 J2EE 的外部可以通过资源适配器直接调用部署在 J2EE 中的应用,如 EJB。
下面简单看一下 JCA 的体系结构,如图 1 所示。
图 1 JCA 的体系结构
下面解释一下上图中的一些概念。
资源适配器(Resource Adapter):为了获得在应用服务器和 EIS 之间的系统标准可插入性,JCA 定义了应用服务器和 EIS 之间的一系列合约(Contract),资源适配器实现了 EIS 端的系统级合约。
系统级合同(System Contract):系统级合同定义了一组系统合同,可以让应用服务器和资源适配器连接起来以管理连接、事务和安全性。这样,应用组件的开发者就可以把精力集中与和业务逻辑相关的开发,而没有必要关心系统级的问题。
客户通用接口(CCI):定义了 J2EE 组件连接到 EIS 系统的一组通用的 API,这些 API 在具体的开发中进行实现。
在连接器的开发中,主要任务就是开发资源适配器。如果需要,再开发出一套客户通用接口实现(CCI),这样,客户端就可以通过这些通用的接口来连接、使用 EIS 层的资源了。
在使用连接池的情况下,应用程序组件和 JCA 以及 EIS 交互关系如图 2 所示。
图 2 应用程序组件和 JCA 以及 EIS 交互之间的交互关系
我们简要看一下请求传递的顺序:
- 应用程序组件发出获得连接的请求;
- 连接工厂调用连接管理器的 allocateConnection;
- 连接管理器向连接池管理器发出获得连接的请求;
- 连接池管理器试图从 ManagedConnectionFactory 进行连接匹配,如果没有匹配到连接,那么返回 null;
- 由于没有匹配到连接,连接池管理器调用 ManagedConnectionFactory 的 createManagedConnection 方法来创建连接;
- ManagedConnectionFactory 接收到连接池管理器的请求后,创建一个 ManagedConnection 实例,同时 ManagedConnection 打开和 EIS 之间的物理连接,然后把这个 ManagedConnection 实例返回给连接池管理器;
- 连接池管理器调用 ManagedConnection 实例的 getConnection 方法以获得一个 Connection 实例;
- ManagedConnection 实例收到连接池管理器的 getConnection 请求后,创建一个 Connection 实例,然后把这个实例返回给连接池管理器;
- 这个 Connection 实例通过连接池管理顺次返回给应用程序组件;
- 应用程序组件通过返回的 Connection 来创建 Interaction 或者调用业务方法;
- 应用程序组件通过 Connection 调用业务方法时,实际上 Connection 使用了 ManagedConnection 的物理连接和 EIS 进行交互。
下面我们介绍一个简单的案例的开发。
这个案例使用了典型的 J2EE 多层体系结构,如图 3 所示。EIS 层是一个简单的能处理多线程的 Socket 服务程序,当它接收到客户端发送来的字符串时,就在这个字符串前增加"Hello:"字符串,然后返回。资源适配器用于连接到 EIS,使得 J2EE 应用(如 EJB)能够通过它调用 EIS 层。这个案例的客户端有两种,一种是基于浏览器的客户端,它通过 HTTP 来访问 Web 服务器上的 JSP 组件,JSP 组件通过 RMI 调用 EJB 来访问 EIS;另一种客户端是普通的 Java 程序,它通过 RMI 来调用部署在 EJB 服务器中的 EJB 组件以访问 EIS。
图 3 案例体系结构
下面我们看简单资源层的代码。
资源层是一个 Socket 服务程序,当它接收到客户端发送来的字符串时,就在这个字符串前增加"Hello:"字符串,然后返回这个新的字符串。代码如例程 1 所示。
例程 1 EIS 资源层
package com.hellking.jca.eis;
import java.net.*;
import java.io.*;
public class EISServer
{
public static void main(String[] args)
{
try
{
System.out.println ("启动服务 ....");
ServerSocket s = new ServerSocket (2008);
// 处理客户端请求
while (true)
{
System.out.println ("监听客户端连接 ...");
new ServerThread(s.accept()).start();
System.out.println ("接收到一个连接");
}
}
catch(Exception e)
{
e.printStackTrace(System.err);
}
}
}
class ServerThread extends Thread
{
private Socket socket=null;
public ServerThread(Socket socket)
{
super("a new thread");
this.socket=socket;
}
public void run()
{
try
{
BufferedReader in = new BufferedReader
(new InputStreamReader (socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
String line;
do
{
line = in.readLine();
System.out.println ("接收到以下输入 : " + line);
if (line != null)
{
out.println ("Hello: "+line);
}
} while (line != null);
System.out.println ("关闭连接");
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
|
开发资源适配器,我们从最基本的连接(Connection)类开始。
DemoConnection
DemoConnection 扩展了 CCI 的 Connection 接口,它由客户端程序使用,代表了到 EIS 的"虚拟"连接,通过这个"虚拟"的连接客户端可以调用 EIS。需要注意的是,虚拟连接关闭时,物理连接不一定关闭。DemoConnection 定义了资源适配器所实现的业务方法。如例程 2 所示。
例程 2 DemoConnection 的代码
package com.hellking.jca;
import javax.resource.cci.Connection;
import javax.resource.ResourceException;
public interface DemoConnection extends Connection
{
// 业务方法
public String sayHello(String name)throws ResourceException;
}
|
DemoConnectionImpl
DemoConnectionImpl 是 DemoConnection 的实现类,它通过 ManagedConnection 来完成具体的业务方法。ManagedConnection 是代表到 EIS 的物理连接,将在后面介绍。
例程 3 DemoConnectionImpl 大代码
package com.hellking.jca;
import javax.resource.*;
import javax.resource.spi.*;
import javax.resource.cci.*;
import javax.security.auth.*;
import java.util.*;
import java.io.*;
// 连接实现类,它通过 DemoManagedConnection 来完成具体的任务
public class DemoConnectionImpl implements DemoConnection
{
protected PrintWriter out;//logOut
protected DemoManagedConnection demoManagedConnection;
// 关闭连接,释放资源
public void close()
{
if (demoManagedConnection == null) return;
demoManagedConnection.removeConnection(this);
demoManagedConnection.connectionClosedEvent();
demoManagedConnection = null;
}
// 返回和这个连接关联的被管理连接
public DemoManagedConnection getManager()
{
return demoManagedConnection;
}
// 设置和这个连接关联的被管理连接
public void setManager (DemoManagedConnection manager)
{
this.demoManagedConnection =manager;
}
// 业务方法,它通过调用被管理的连接来实现。
public String sayHello(String name)throws ResourceException
{
return demoManagedConnection.sayHello (name);
}
// 使连接无效
public void invalidate()
{
demoManagedConnection = null;
}
public void setLogWriter(PrintWriter out)
{
this.out = out;
}
public PrintWriter getLogWriter()
{
return out;
}
public ConnectionMetaData getMetaData()
{
return null;
}
public ResultSetInfo getResultSetInfo()
{
return null;
}
public javax.resource.cci.LocalTransaction getLocalTransaction()
{
return null;
}
public Interaction createInteraction()
{
return null;
}
}
|
DemoConnectionFactoryImpl
DemoConnectionFactoryImpl 也是和 CCI 相关的类,它实现了 ConnectionFactory 接口,它主要用于创建客户端要使用的虚拟连接(DemoConnection)。由于 DemoConnectionFactoryImpl 类需要在 JNDI 名字空间中注册,故它需实现 Serializable 和 Referenceable 接口。客户端查找 DemoConnectionFactoryImpl 类,然后使用这个类来获得到 EIS 的连接。DemoConnectionFactoryImpl 代码如例程 4 所示。
例程 4 DemoConnectionFactoryImpl 的代码
package com.hellking.jca;
import javax.resource.*;
import javax.resource.spi.*;
import javax.resource.cci.*;
import javax.naming.*;
import java.io.*;
public class DemoConnectionFactoryImpl implements ConnectionFactory
{
protected Reference reference;
protected ManagedConnectionFactory manager;
protected ConnectionManager connectionManager;
protected PrintWriter out;//logOut
// 构造方法
public DemoConnectionFactoryImpl (ManagedConnectionFactory manager,
ConnectionManager connectionManager)
{
this.manager = manager;
// 如果连接管理器为空,那么创建一个新的连接管理器
if (connectionManager == null)
{
connectionManager = new DemoConnectionManager();
((DemoConnectionManager)connectionManager).setLogWriter (out);
}
else
{
this.connectionManager = connectionManager;
}
}
// 获得一个连接
public Connection getConnection() throws ResourceException
{
return (DemoConnection)
connectionManager.allocateConnection (manager, null);
}
// 不支持此方法
public Connection getConnection(ConnectionSpec p) throws ResourceException
{
return null;
}
public void setReference(Reference ref)
{
reference = ref;
}
public Reference getReference()
{
return reference;
}
public void setLogWriter(PrintWriter _out)
{
out = _out;
}
public PrintWriter getLogWriter()
{
return out;
}
public RecordFactory getRecordFactory() throws ResourceException
{
return null;
}
public ResourceAdapterMetaData getMetaData()
{
return null;
}
}
|
DemoConnectionManager
DemoConnectionManager 是连接的管理器,它为资源适配器把连接请求传递给应用服务器提供了一个切入点。应用服务器实现 DemoConnectionManager 接口,这个实现不针对具体的资源适配器和连接工厂接口。DemoConnectionManager 的任务就是分配连接。对于一些高级的应用,DemoConnectionManager 通过和连接池交互来分配连接,在我们开发的这个案例中,DemoConnectionManager 直接使用 ManagedConnectionFactory 来分配连接。ManagedConnectionFactory 的代码如例程 5 所示。
例程 5 ManagedConnectionFactory 的代码
package com.hellking.jca;
import java.io.Serializable;
import java.io.PrintWriter;
import javax.resource.ResourceException;
import javax.resource.spi.*;
public class DemoConnectionManager
implements ConnectionManager, Serializable
{
protected PrintWriter out;
// 分配一个连接
public Object allocateConnection (
ManagedConnectionFactory managedConnectionFactory,
ConnectionRequestInfo connectionRequestInfo)
throws ResourceException
{
ManagedConnection managedConnection =
managedConnectionFactory.createManagedConnection(null,
connectionRequestInfo);
return managedConnection.getConnection(null, connectionRequestInfo);
}
public void setLogWriter(java.io.PrintWriter out)
{
this.out =out;
}
}
|
DemoManagedConnectionMetaData
DemoManagedConnectionMetaData 提供了和 ManagedConnection 关联的后台 EIS 实例的信息。应用服务器通过这个接口来获得与它连接的 EIS 实例的运行环境信息。DemoManagedConnectionMetaData 的代码如例程 6 所示。
例程 6 DemoManagedConnectionMetaData 的代码
package com.hellking.jca;
import javax.resource.spi.*;
public class DemoManagedConnectionMetaData
implements ManagedConnectionMetaData
{
protected DemoManagedConnection demoManagedConnection;
public DemoManagedConnectionMetaData (
DemoManagedConnection demoManagedConnection)
{
this.demoManagedConnection = demoManagedConnection;
}
// 获得 EIS 的提供商
public String getEISProductName()
{
return "Hellking's Simple EIS server";
}
// 获得 EIS 产品的版本
public String getEISProductVersion()
{
return "Version 1.2";
}
//eis 支持的最大连接数
public int getMaxConnections()
{
return 10000;
}
public String getUserName()
{
return "Hellking";
}
}
|
DemoManagedConnection
DemoManagedConnection 是资源适配器的关键所在,它代表了和 EIS 的物理连接,前面介绍的 DemoConnection 是由客户端使用的虚拟连接,虚拟连接要通过物理连接才能使用 EIS。一个物理连接可以被多个虚拟连接使用,可以通过 associateConnection 方法来把虚拟连接和物理连接进行关联。DemoManagedConnection 也提供了产生虚拟连接实例的方法。DemoManagedConnection 的代码如例程 7 所示。
例程 7 DemoManagedConnection 的代码
package com.hellking.jca;
import javax.resource.*;
import javax.resource.spi.*;
import javax.security.auth.*;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.transaction.xa.*;
//DemoManagedConnection 代表了到 EIS 的物理的连接
public class DemoManagedConnection implements ManagedConnection
{
protected Socket socket;// 和 server 连接的 Socket
protected PrintStream serverStream;//
protected BufferedReader serverBufferedReader;
protected boolean destroyed;// 是否销毁
protected PrintWriter out;
protected Set connections = new HashSet();// 被管理的连接
protected Set connectionListeners = new HashSet();// 连接监听器
DemoManagedConnectionFactory factory;// 连接工厂
public DemoManagedConnection(DemoManagedConnectionFactory factory)
{
this.factory = factory;
}
// 为连接增加事件监听器
public void addConnectionEventListener(ConnectionEventListener l)
{
connectionListeners.add(l);
}
// 清除连接监听器
public void removeConnectionEventListener(ConnectionEventListener l)
{
connectionListeners.remove(l);
}
// 返回连接工厂
public DemoManagedConnectionFactory getFactory ()
{
return factory;
}
// 增加一个连接 , 并且返回它
public Object getConnection (Subject subject,
ConnectionRequestInfo cxRequestInfo)
{
DemoConnectionImpl connection = new DemoConnectionImpl();
connection.setManager(this);
connection.setLogWriter (out);
addConnection(connection);
return connection;
}
// 清除占用的资源
public void cleanup() throws ResourceException
{
destroyedError();
Iterator it = connections.iterator();
while (it.hasNext())
{
DemoConnectionImpl demoConnectionImpl = (DemoConnectionImpl) it.next();
demoConnectionImpl.invalidate();
}
connections.clear();
}
// 销毁所有的物理连接
public void destroy()
{
if (destroyed) return;
Iterator it = connections.iterator();
while (it.hasNext())
{
DemoConnectionImpl DemoConnectionImpl =
(DemoConnectionImpl) it.next();
DemoConnectionImpl.invalidate();
}
connections.clear();
if (socket != null)
try {socket.close();}
catch (Exception e){}
destroyed = true;
}
// 把一个 Connection 和这个被管理的连接关联
public void associateConnection(Object _connection)
throws ResourceException
{
destroyedError();
if (_connection instanceof DemoConnection)
{
DemoConnectionImpl connection =
(DemoConnectionImpl)_connection;
DemoManagedConnection demoManagedConnection = connection.getManager();
if (demoManagedConnection == this) return;
try
{
demoManagedConnection.removeConnection(connection);
}
catch(Exception e)
{
}
addConnection(connection);
connection.setManager (this);
}
else
{
throw new javax.resource.spi.IllegalStateException
("Invalid connection object: " + _connection);
}
}
// 不支持此方法
public XAResource getXAResource() throws ResourceException
{
throw new NotSupportedException("不支持分布式事务");
}
// 不支持此方法
public LocalTransaction getLocalTransaction()
throws ResourceException
{
throw new NotSupportedException ("Local transaction not supported");
}
// 返回元数据
public ManagedConnectionMetaData getMetaData()
{
return new DemoManagedConnectionMetaData(this);
}
protected void destroyedError()
throws javax.resource.spi.IllegalStateException
{
if (destroyed)
throw new javax.resource.spi.IllegalStateException
("DemoManagedConnection 已经销毁");
}
// 增加一个和此被管理连接(ManagedConnection)关联连接(Connection)
protected void addConnection(DemoConnection connection)
{
connections.add(connection);
}
// 删除一个和此被管理连接(ManagedConnection)关联连接(Connection)
protected void removeConnection(DemoConnection connection)
{
connections.remove(connection);
}
// 设置 LogWriter
public void setLogWriter(PrintWriter _out)
{
out = _out;
}
public PrintWriter getLogWriter()
{
return out;
}
// 判断是否已经销毁
public boolean isDestroyed()
{
return destroyed;
}
// 关闭连接的事件,释放资源,由连接监听器来处理
void connectionClosedEvent()
{
Iterator it = connectionListeners.iterator();
while (it.hasNext())
{
ConnectionEventListener listener =
(ConnectionEventListener) it.next();
listener.connectionClosed
(new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED));
}
}
// 打开物理连接,物理连接是和 EIS 的正在的连接。通过 Socket 来进行通信
public void openPhysicalConnection (String serverName, int portNumber)
throws UnknownHostException, IOException
{
socket = new Socket (serverName, portNumber);
serverStream = new PrintStream (socket.getOutputStream());
serverBufferedReader = new BufferedReader
(new InputStreamReader (socket.getInputStream()));
}
// 业务方法,它是同步的,同时只能一个和 Server 进行通信
public synchronized String sayHello(String name)
throws ResourceException
{
serverStream.println (name);
try
{
String in = serverBufferedReader.readLine();
return in;
}
catch (Exception e)
{
throw new ResourceException
("调用 sayHello() 发生错误 : " + e.toString());
}
}
}
|
DemoManagedConnectionFactory
DemoManagedConnectionFactory 是 DemoManagedConnection 的工厂,它的主要任务是创建和匹配 DemoManagedConnection 实例,在创建 DemoManagedConnection 实例时,DemoManagedConnection 实例同时打开到 EIS 的物理连接。DemoManagedConnectionFactory 的代码如例程 8 所示。
例程 8 DemoManagedConnectionFactory 的代码
package com.hellking.jca;
import javax.resource.*;
import javax.resource.spi.*;
import javax.security.auth.*;
import java.util.Set;
import java.util.Iterator;
import java.io.*;
public class DemoManagedConnectionFactory
implements ManagedConnectionFactory, Serializable
{
protected PrintWriter out = new PrintWriter(System.out);
private int port;// 连接 EIS 的端口
private String server;//eis 服务器的 url
// 创建连接工厂,指定连接工厂的连接管理者为 connectionManager
public Object createConnectionFactory
(ConnectionManager connectionManager)
{
DemoConnectionFactoryImpl demoConnectionFactoryImpl =
new DemoConnectionFactoryImpl (this, connectionManager);
demoConnectionFactoryImpl.setLogWriter(out);
return demoConnectionFactoryImpl;
}
// 创建连接工厂,没有指定连接管理者
public Object createConnectionFactory()
{
DemoConnectionFactoryImpl demoConnectionFactoryImpl =
new DemoConnectionFactoryImpl (this, null);
demoConnectionFactoryImpl.setLogWriter(out);
return demoConnectionFactoryImpl;
}
// 创建被管理的连接 , 被管理的连接是和 EIS 的真实连接,它是物理连接。
public ManagedConnection createManagedConnection(Subject subject,
ConnectionRequestInfo cri)
throws ResourceException
{
DemoManagedConnection demoManagedConnection =
new DemoManagedConnection(this);
demoManagedConnection.setLogWriter(out);
try
{
// 打开物理连接
System.out.println("打开物理连接 .....");
demoManagedConnection.openPhysicalConnection (server, port);
return demoManagedConnection;
}
catch (IOException e)
{
throw new ResourceException (e.toString());
}
}
// 匹配被管理的连接 , 如果匹配到连接,则返回,否则返回 null
public ManagedConnection matchManagedConnections
(Set connections, Subject subject, ConnectionRequestInfo cri)
{
Iterator it = connections.iterator();
while (it.hasNext())
{
Object obj = it.next();
if (obj instanceof DemoManagedConnection)
{
DemoManagedConnection demoManagedConnection =
(DemoManagedConnection) obj;
DemoManagedConnectionFactory demoManagedConnectionf =
demoManagedConnection.getFactory();
if (demoManagedConnectionf.equals(this))
{
return demoManagedConnection;
}
}
}
return null;
}
public int hashCode()
{
if (server == null) return 0;
return server.hashCode();
}
// 判断两个被管理的连接工厂是否相等
public boolean equals(Object o)
{
if (o == null) return false;
if (!(o instanceof DemoManagedConnectionFactory))
return false;
DemoManagedConnectionFactory other =
(DemoManagedConnectionFactory)o;
if (server.equalsIgnoreCase(other.server) &&
port == other.port) return true;
return false;
}
public void setLogWriter(java.io.PrintWriter out)
{
this.out = out;
}
public PrintWriter getLogWriter()
{
return out;
}
public void setServer (String server)
{
this.server = server;
}
public String getServer ()
{
return server;
}
public void setPort (Integer port)
{
this.port = port.intValue();
}
public Integer getPort ()
{
return new Integer(port);
}
}
|
在 DemoManagedConnectionFactory 类中,设置了两个属性,Port 和 Server,Port 表示连接 EIS 使用的端口,Server 表示连接 EIS 时使用的 URL。这两个属性需要在资源适配器的部署描述符里指定具体的值。
下面的任务就是在部署描述符里指定资源适配器的相关接口和实现类。具体需要指定以下的接口和类:
- ManagedConnectionFactory,这里是 DemoManagedConnectionFactory;
- Connectionfactory 的接口,这里是 javax..resource.cci.ConnectionFactory;
- Connectionfactory 的实现类,这里是 DemoConnectionFactoryImpl;
- 连接的接口,这里是 DemoConnection;
- 连接的实现类,这里是 DemoConnectionImpl。
另外,还需要指定以下的属性:
- 是否支持事务,这里是 NoTransaction;
- 安全认证的支持,这里是 false;
- DemoManagedConnectionFactory 中使用的属性,其中 Server 的值为 localhost,Port 的值为 2008。
例程 9 是资源适配器的具体内容,它要保存为 ra.xml 放在资源适配器打包文件 RAR 的 META-INF 目录下。
例程 9 资源适配器的具体内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE connector PUBLIC '-//Sun Microsystems, Inc.//DTD Connector 1.0//EN'
'http://java.sun.com/dtd/connector_1_0.dtd'>
<connector>
<display-name>DemoRA</display-name>
<vendor-name>HELLKING</vendor-name>
<spec-version>1.0</spec-version>
<eis-type>NO TRANS</eis-type>
<version>1.2</version>
<resourceadapter>
<managedconnectionfactory-class>com.hellking.jca.DemoManagedConnectionFactory
</managedconnectionfactory-class>
<connectionfactory-interface>javax.resource.cci.ConnectionFactory
</connectionfactory-interface>
<connectionfactory-impl-class>com.hellking.jca.DemoConnectionFactoryImpl
</connectionfactory-impl-class>
<connection-interface>com.hellking.jca.DemoConnection
</connection-interface>
<connection-impl-class>com.hellking.jca.DemoConnectionImpl
</connection-impl-class>
<transaction-support>NoTransaction</transaction-support>
<config-property>
<config-property-name>Server</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>localhost</config-property-value>
</config-property>
<config-property>
<config-property-name>Port</config-property-name>
<config-property-type>java.lang.Integer</config-property-type>
<config-property-value>2008</config-property-value>
</config-property>
<reauthentication-support>false</reauthentication-support>
</resourceadapter>
</connector>
|
通过上面的介绍,相信读者都 JCA 的体系结构和开发已经有了全面的了解。
下一节介绍资源适配器客户端的开发,并且在不同的应用服务器平台下部署这个 J2EE 应用和资源适配器。
陈亚强:北京华园天一科技有限公司高级软件工程师,擅长J2EE技术,曾参与多个J2EE项目的设计和开发,对Web服务有很大的兴趣并且有一定的项目经验。热爱学习,喜欢新技术,曾参与多本图书的写作。好交朋友,您可以通过 cyqcims@mail.tsinghua.edu.cn和他联系。